5-3 网络编程—编写服务端与客户端demo

1. 编写简易客户端与服务端程序

图片说明

1.1 服务端构建流程

如上图所示,使用Socket API建立简易的TCP服务端过程为:

    1. 建立一个socket()
    1. 绑定接受客户端连接的端口 bind()
    1. 监听网络端口 listen()
    1. 等待接受客户端连接 accept()
    1. 向客户端发送一条数据 send()
    1. 接收客户端发送的数据 recv()
    1. 关闭socket()

1.2 服务端源码

//
// Created by Evila on 2021/6/27.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<iostream>
using namespace std;

int main(int argc, char** argv)
{
		//	1. 建立一个Socket
		// 参数 ipv4 面向字节流的 tcp协议
		int _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if( _sock < 0)
		{
				cout << "create socket error: " << strerror(errno) << "%s(errno: " << errno << endl;
				exit(0);
		}

		//	2. 绑定端口45678
		sockaddr_in _sin = {};    // sockaddr_in为网络地址的结构体
		_sin.sin_family = AF_INET;  // 设置协议类型
		int _port = 45678;
		_sin.sin_port = htons(_port); // 设置协议源端口号
		// 计算机数据表示存在两种字节顺序:
		// 网络字节顺序(Network Byte Order, NBO)与主机字节顺序(Host Byte Order, HBO)
		// NBO是大端模式(big-endian),也就是整数的高位字节存放在内存的低地址处
		// 在网络上使用统一的网络字节顺序,可以避免兼容性问题
		// 而主机字节序与CPU或操作系统相关, 无法统一; 因此使用htons()将主机字节序转换成网络字节序
		_sin.sin_addr.s_addr = htonl(INADDR_ANY); // 协议源地址 随机ip
		if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == -1)  //sockaddr 不利于编码
		{
				cout << "ERROR: 绑定用于接受客户端连接的网络端口失败..." << endl;
				exit(0);
		}
		else
		{
				cout << "SUCCESS: 绑定端口" << _port << "成功..." << endl;
		}

		//	3. 监听网络端口 listen
		if (listen(_sock, 5) == -1) // 第二个参数 backbag 为连接为完成队列长度
		{
				cout << "ERROR: 监听用于接受客户端连接的网络端口失败..." << endl;
				exit(0);
		}
		else
		{
				cout << "SUCCESS: 监听端口成功..." << endl;
		}

		//	4. 等待接受客户端连接 accept
		sockaddr_in _clientAddr = {};
		int cliendAddrLen = sizeof(_clientAddr);
		int _clientSock = -1; // 初始化无效的socket 用来存储接入的客户端

		char msgBuf[] = "Hello, I'm Server";
		char recvBuff[2048];

		// 这里为了方便测试 只接受10次连接就关闭
		int n = 10;
		while (n--)
		{
				// 当客户端接入时 accept函数会得到客户端的socket地址和长度
				_clientSock = accept(_sock, (sockaddr*)&_clientAddr, (socklen_t *)&cliendAddrLen);
				if (-1 == _clientSock) //接受到无效接入
				{
						cout << "ERROR: 接受到无效客户端SOCKET..." << endl;
						continue;
				}
				else
				{
						//inet_ntoa 将ip地址转换成可读的字符串
						cout << "新Client加入: IP = " << inet_ntoa(_clientAddr.sin_addr) << endl;
						//	5. 向客户端发送数据 send()
						send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0); // +1是为了把\0算进去
				}

				int recvLen = recv(_clientSock, recvBuff, 2048, 0);
				recvBuff[recvLen] = '\0';   // 设置字符串结束符
				cout << "recv msg from client: " << recvBuff << endl;
		}

		// 7. 关闭socket
		close(_sock);
		return 0;
}

1.3 编译并运行

使用g++命令编译并生成可执行文件server,执行后该进程阻塞在accept()函数处。 图片说明

1.4 客户端源码

//
// Created by Evila on 2021/6/27.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char** argv)
{
		// 1. 建立一个Socket
		int _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (_sock < 0)
		{
				cout << "create socket error: " << strerror(errno) << "%s(errno: " << errno << endl;
				exit(0);
		}

		// 2. 设置请求连接的server 地址
		sockaddr_in _sevrAddr = {};    // sockaddr_in为网络地址的结构体
		_sevrAddr.sin_family = AF_INET;
		int port = 45678;
		_sevrAddr.sin_port = htons(port);

		string server_ip;
		cout << "please input server ip: ";
		cin >> server_ip;

		if (inet_pton(AF_INET, server_ip.c_str(), &_sevrAddr.sin_addr) <= 0)
		{
				cout <<"inet_pton error for " << server_ip << endl;
				exit(0);
		}

		// 3. 连接服务端
		int ret = connect(_sock, (struct sockaddr*)&_sevrAddr, sizeof(_sevrAddr));
		if (ret < 0)
		{
				cout << "connect error: " << strerror(errno) << "errno: " << errno << endl;
				exit(0);
		}
		else
		{
				cout << "connect to server: " << server_ip << ":" << port << " success!" << endl;
		}

		// 4. 向服务端发送数据
		

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++岗面试真题解析 文章被收录于专栏

<p> C++工程师面试真题解析! </p> <p> 邀请头部大厂创作者<a href="https://www.nowcoder.com/profile/73627192" target="_blank">@Evila</a> 及牛客教研共同打磨 </p> <p> 助力程序员的求职! </p>

全部评论

相关推荐

Yushuu:你的确很厉害,但是有一个小问题:谁问你了?我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了😆
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务