C++网络编程学习:建立基础TCP服务端/客户端

网络编程学习记录

  • 使用的语言为C/C++
  • 源码支持的平台为:Windows

笔记一:建立基础TCP服务端/客户端  点我跳转
笔记二:网络数据报文的收发  点我跳转
笔记三:升级为select网络模型  点我跳转
笔记四:跨平台支持Windows、Linux系统  点我跳转
笔记五:源码的封装  点我跳转
笔记六:缓冲区溢出与粘包分包  点我跳转
笔记七:服务端多线程分离业务处理高负载  点我跳转


一、建立简易TCP服务端

1.建立服务端大致流程

  1. 建立一个套接字 (socket)
  2. 绑定客户端连接的端口 (bind)
  3. 监听网络端口 (listen)
  4. 等待接受客户端连接 (accept)
  5. 接收客户端发送的数据 (recv)
  6. 向客户端发送数据 (send)
  7. 关闭套接字 (closesocket)

2.代码实现以及详细注释

#define WIN32_LEAN_AND_MEAN//消除下面两个头文件存在的冲突

#include<winSock2.h>//此头文件应在windows.h头文件的上面,否则会有冲突
#include<windows.h>
#include<bits/stdc++.h>

#pragma comment(lib,"ws2_32.lib")//链接此动态链接库 windows特有 

using namespace std; 
 
int main() 
{
    
    
	//启动windows socket 2,x环境 windows特有 
	WORD ver = MAKEWORD(2,2);//WinSock库版本号 
	WSADATA dat;//网络结构体 储存WSAStartup函数调用后返回的Socket数据 
	if(0 != WSAStartup(ver,&dat))//正确初始化后返回0 
	{
    
    
		return 0;
	}
	
	//建立一个socket 
	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//IPV4 数据流类型 TCP类型 
	if(INVALID_SOCKET == _mysocket)//建立失败 
    {
    
       
        return 0;  
    } 
    
	//绑定网络端口和IP地址 
	sockaddr_in _myaddr = {
    
    };//建立sockaddr结构体  sockaddr_in结构体方便填写 但是下面要进行类型转换 
	_myaddr.sin_family = AF_INET;//IPV4
	_myaddr.sin_port = htons(8888);//端口 host to net unsigned short
	_myaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//网络地址 INADDR_ANY监听所有网卡的端口 
	if(SOCKET_ERROR == bind(_mysocket,(sockaddr*)&_myaddr,sizeof(sockaddr_in)))//socket (强制转换)sockaddr结构体 结构体大小 
	{
    
    
		cout<<"绑定不成功"<<endl;
	}
	else
	{
    
    
		//cout<<"绑定成功"<<endl; 
	}
	
	//监听网络端口
	if(SOCKET_ERROR == listen(_mysocket,5))//套接字 最大多少人连接 
	{
    
    
		cout<<"监听失败"<<endl;
	}
	else
	{
    
    
		//cout<<"监听成功"<<endl; 
	}
	
	//等待接收客户端连接
	sockaddr_in _clientAddr = {
    
    };//新建sockadd结构体接收客户端数据 
	int _addr_len = sizeof(sockaddr_in);//获取sockadd结构体长度 
	SOCKET _temp_socket = INVALID_SOCKET;//声明客户端套接字 
	char _buf[256] = {
    
    };//接收客户端发送的消息 
	while(true)
	{
    
    
		_temp_socket = accept(_mysocket,(sockaddr*)&_clientAddr,&_addr_len);//自身套接字 客户端结构体 结构体大小 
		if(INVALID_SOCKET == _temp_socket)//接收失败 
		{
    
    
			cout<<"接收到无效客户端Socket"<<endl;
		}
		else
		{
    
    
			cout<<"新客户端加入"<<endl; 
			printf("IP地址为:%s \n", inet_ntoa(_clientAddr.sin_addr));  
		}
		
		//接收客户端发送的数据 
		char _buf[256] = {
    
    };
		int _buf_len = recv(_temp_socket,_buf,256,0);
		if(_buf_len>0)
		{
    
    
			printf("%s\n",_buf);
		}
		
		//向客户端发送数据
		char _msg[] = "HelloWorld";
		send(_temp_socket,_msg,strlen(_msg)+1,0);//客户端套接字 数据 数据长短 flag 
		
		//关闭客户端socket
		closesocket(_temp_socket); 
	}
	
	//关闭socket 
	closesocket(_mysocket); 
	
	//清除windows socket 环境 
	WSACleanup(); 
	
	return 0;
}

二、建立简易TCP客户端

1.建立客户端大致流程

  1. 建立一个套接字 (socket)
  2. 连接服务器 (connect)
  3. 向客户端发送数据 (send)
  4. 接收客户端发送的数据 (recv)
  5. 关闭套接字 (closesocket)

2.代码实现以及详细注释

#define WIN32_LEAN_AND_MEAN

#include<winSock2.h>
#include<windows.h>
#include<bits/stdc++.h>

#pragma comment(lib,"ws2_32.lib")//链接此动态链接库 windows特有 

using namespace std; 
 
int main()
{
    
    
	//启动windows socket 2,x环境 windows特有 
	WORD ver = MAKEWORD(2,2);//WinSock库版本号 
	WSADATA dat;//网络结构体 储存WSAStartup函数调用后返回的Socket数据 
	if(0 != WSAStartup(ver,&dat))//正确初始化后返回0 
	{
    
    
		return 0;
	}
	
	//建立一个socket 
	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,0);//IPV4 数据流类型 类型可以不用写 
	if(INVALID_SOCKET == _mysocket)//建立失败 
    {
    
       
        return 0;  
    } 
    
    //连接服务器
    sockaddr_in _sin = {
    
    };//sockaddr结构体 
    _sin.sin_family = AF_INET;//IPV4
    _sin.sin_port = htons(8888);//想要连接的端口号 
	_sin.sin_addr.S_un.S_addr =  inet_addr("127.0.0.1");//想要连接的IP 
	if(SOCKET_ERROR == connect(_mysocket,(sockaddr*)&_sin,sizeof(sockaddr_in)))
	{
    
    
		cout<<"连接失败"<<endl;
		closesocket(_mysocket);
	}
	else
	{
    
    
		cout<<"连接成功"<<endl; 
	}
	
	//向客户端发送数据
	char _msg[] = "HelloServer";
	send(_mysocket,_msg,strlen(_msg)+1,0);//客户端套接字 数据 数据长短 flag 
	
	//接收服务器信息 
	char _buf[256] = {
    
    };
	int _buf_len = recv(_mysocket,_buf,256,0);
	if(_buf_len>0)
	{
    
    
		printf("%s\n",_buf);
	}
	
	//关闭socket
	closesocket(_mysocket); 
	
	//清除windows socket 环境 
	WSACleanup(); 
	
	return 0;
} 

三、建立可持续处理请求的网络程序

1.思路

  在进行socket连接后,即服务端进行accept操作、客户端进行connect操作后,使用循环,在此循环中进行send/recv操作传输数据,即可实现持续处理请求。

2.代码实现以及详细注释

2.1 服务端代码

#define WIN32_LEAN_AND_MEAN

#include<winSock2.h>
#include<windows.h>
#include<bits/stdc++.h>

#pragma comment(lib,"ws2_32.lib")//链接此动态链接库 windows特有 

using namespace std; 
 
int main() 
{
    
    
	//启动windows socket 2,x环境 windows特有 
	WORD ver = MAKEWORD(2,2);//WinSock库版本号 
	WSADATA dat;//网络结构体 储存WSAStartup函数调用后返回的Socket数据 
	if(0 != WSAStartup(ver,&dat))//正确初始化后返回0 
	{
    
    
		return 0;
	}
	
	//建立一个socket 
	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//IPV4 数据流类型 TCP类型 
	if(INVALID_SOCKET == _mysocket)//建立失败 
    {
    
       
        return 0;  
    } 
    
	//绑定网络端口和IP地址 
	sockaddr_in _myaddr = {
    
    };//建立sockaddr结构体  sockaddr_in结构体方便填写 但是下面要进行类型转换 
	_myaddr.sin_family = AF_INET;//IPV4
	_myaddr.sin_port = htons(8888);//端口 host to net unsigned short
	_myaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//网络地址 INADDR_ANY监听所有网卡的端口 
	if(SOCKET_ERROR == bind(_mysocket,(sockaddr*)&_myaddr,sizeof(sockaddr_in)))//socket (强制转换)sockaddr结构体 结构体大小 
	{
    
    
		cout<<"绑定不成功"<<endl;
	}
	else
	{
    
    
		//cout<<"绑定成功"<<endl; 
	}
	
	//监听网络端口
	if(SOCKET_ERROR == listen(_mysocket,5))//套接字 最大多少人连接 
	{
    
    
		cout<<"监听失败"<<endl;
	}
	else
	{
    
    
		//cout<<"监听成功"<<endl; 
	}
	
	//等待接收客户端连接
	sockaddr_in _clientAddr = {
    
    };//新建sockadd结构体接收客户端数据 
	int _addr_len = sizeof(sockaddr_in);//获取sockadd结构体长度 
	SOCKET _temp_socket = INVALID_SOCKET;//声明客户端套接字 
	char _buf[256] = {
    
    };//接收客户端发送的消息 
	
	_temp_socket = accept(_mysocket,(sockaddr*)&_clientAddr,&_addr_len);//自身套接字 客户端结构体 结构体大小 
	if(INVALID_SOCKET == _temp_socket)//接收失败 
	{
    
    
		cout<<"接收到无效客户端Socket"<<endl;
	}
	else
	{
    
    
		cout<<"新客户端加入"<<endl; 
		printf("IP地址为:%s \n", inet_ntoa(_clientAddr.sin_addr));  
	}
	
	while(true)//循环
	{
    
    
		//接收客户端发送的数据 
		int _buf_len = recv(_temp_socket,_buf,256,0);
		if(_buf_len<=0)
		{
    
    
			printf("客户端已退出\n");
			break;
		}
		if(0 == strcmp(_buf,"getname"))
		{
    
    
			//向客户端发送数据
			char _msg[] = "My name is Mr.Zhao";
			send(_temp_socket,_msg,strlen(_msg)+1,0);//客户端套接字 数据 数据长短 flag 
		}
		else if(0 == strcmp(_buf,"getage"))
		{
    
    
			//向客户端发送数据
			char _msg[] = "My age is 19";
			send(_temp_socket,_msg,strlen(_msg)+1,0);//客户端套接字 数据 数据长短 flag 
		}
		else
		{
    
    
			//向客户端发送数据
			char _msg[] = "???";
			send(_temp_socket,_msg,strlen(_msg)+1,0);//客户端套接字 数据 数据长短 flag 
		}
	}

	//关闭客户端socket
	closesocket(_temp_socket);

	//关闭socket 
	closesocket(_mysocket); 
	
	//清除windows socket 环境 
	WSACleanup();
	
	printf("任务结束,程序已退出"); 
	 
	getchar(); 
	
	return 0;
}

2.2 客户端代码

#define WIN32_LEAN_AND_MEAN

#include<winSock2.h>
#include<windows.h>
#include<bits/stdc++.h>

#pragma comment(lib,"ws2_32.lib")//链接此动态链接库 windows特有 

using namespace std; 
 
int main()
{
    
    
	//启动windows socket 2,x环境 windows特有 
	WORD ver = MAKEWORD(2,2);//WinSock库版本号 
	WSADATA dat;//网络结构体 储存WSAStartup函数调用后返回的Socket数据 
	if(0 != WSAStartup(ver,&dat))//正确初始化后返回0 
	{
    
    
		return 0;
	}
	
	//建立一个socket 
	SOCKET _mysocket = socket(AF_INET,SOCK_STREAM,0);//IPV4 数据流类型 类型可以不用写 
	if(INVALID_SOCKET == _mysocket)//建立失败 
    {
    
       
        return 0;  
    } 
    
    //连接服务器
    sockaddr_in _sin = {
    
    };//sockaddr结构体 
    _sin.sin_family = AF_INET;//IPV4
    _sin.sin_port = htons(8888);//想要连接的端口号 
	_sin.sin_addr.S_un.S_addr =  inet_addr("127.0.0.1");//想要连接的IP 
	if(SOCKET_ERROR == connect(_mysocket,(sockaddr*)&_sin,sizeof(sockaddr_in)))
	{
    
    
		cout<<"连接失败"<<endl;
		closesocket(_mysocket);
	}
	else
	{
    
    
		cout<<"连接成功"<<endl; 
	}
	
	while(true)//循环
	{
    
    
		//输入请求 
		char _msg[256] = {
    
    };
		scanf("%s",_msg);
		//处理请求 
		if(0 == strcmp(_msg,"exit"))//退出
		{
    
    
			break;
		}
		else
		{
    
    
			//向客户端发送数据
			send(_mysocket,_msg,strlen(_msg)+1,0);//客户端套接字 数据 数据长短 flag
		}
		//接收服务器信息 
		char _buf[256] = {
    
    };
		int _buf_len = recv(_mysocket,_buf,256,0);
		if(_buf_len>0)
		{
    
    
			printf("%s\n",_buf);
		}
	}

	//关闭socket
	closesocket(_mysocket); 
	
	//清除windows socket 环境 
	WSACleanup(); 
	
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_45698148/article/details/112967657