Windows平台网络通信
参考文章:https://blog.csdn.net/only_write_bug/article/details/148590269?spm=1001.2014.3001.5502
一、环境配置
我们使用Visual Studio 2008版本。
1、导入头文件winsock2.h
2、链接ws2_32.lib库
打开项目的属性页,选中“配置属性”-->"输入"—>“附加依赖项”。也可Alt+F7打开“属性页”。
在右边空白处填入ws2_32.lib。之后我们只需要在源文件中添加头文件winsock2.h即可。
二、Winsock的初始化
进行Winsock编程时,首先调用WSAStartup函数,设置程序中要使用的Winsock版本。并初始化库。
#include <winsock2.h>int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSData);
//成功返回0,失败返回非0的错误码
//wVersionRequested:选中的Winsock版本信息
//lpWSData:WSADATA结构体变量的地址值
/* wVersionRequested:若传递0x0201,表示主版本号1,副版本号2. 高八位为副版本号,低八位为主版本号。也可借助MAKEWORD宏函数构建版本信息MAKEWORD(1,2):主版本号1,副版本号2,返回0x0201.MAKEWORD(2,2):主版本号2,副版本号2,返回0x0202.
*///使用示例
int main()
{WSADATA wsaData;//定义WSADATA 结构体//调用初始化函数if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){printf("WSAStartup error!\n");return 0;}return 0;
}
三、基于Windows的套接字相关函数
#include <winsock2.h>SOCKET socket(int af, int type, int protocol);
/* 成功返回套接字句柄, 失败返回INVALID_SOCKET*/int bind(SOCKET s, const struct sockaddr*name, int namelen);
/* 与Linux系统的bind函数相同,实现IP和端口分配。 成功返回0, 失败返回SOCKET_ERROR*/int listen(SOCKET s, int backlog);
/* 与Linux系统的Listen函数相同,实现接收客户端连接功能, 成功返回0,失败返回SOCKET_ERROR*/SOCKET accept(SOCKET s, struct sockaddr*addr, int *addrLen);
/* 与Linux系统的accept函数相同,实现受理客户端连接请求,成功返回套接字句柄,失败返回INVALID_SOCKET*/int connect(SOCKET s, const struct sockaddr*addr, int addrLen);
/* 与Linux系统的connect函数相同, 实现从客户端发送连接请求的功能,成功返回0,失败返回SOCKET_ERROR */int closesocket(SOCKET s);
/*和Linux系统的close函数相同,实现关闭套接字连接,成功返回0,失败返回SOCKET_ERROR */int send(SOCKET s, const char*buf, int len, int flags);
/*成功返回0,失败返回SOCKET_ERROR */
/*s:传输数据的SOCKET套接字句柄buf:要传输的数据的地址值len:要传输的数据大小,字节数flags:传输数据时用到的多种选项,一般为 0 即可
*/int recv(SOCKET s, const char*buf, int len, int flags);
/*成功返回0,失败返回SOCKET_ERROR */
/*s:接收数据的SOCKET套接字句柄buf:要保存数据的地址值len:要接收的最大数据大小,字节数flags:接收数据时用到的多种选项,一般为 0 即可
*/
四、服务端与客户端创建示例
一、Windows网络通信客户端创建示例
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>int main()
{char buff[100] = "hello, I am Client";char recvbuff[1024] = {0};//接收信息//1、初始化WSADATA结构体对象WSADATA wsaData;//2、初始化WSAStartupif(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){printf("WSAStartup init error!\n");return 0;}//3、初始化套接字 TCP套接字SOCK_STREAM,PF_INET:IPV4互联网协议族SOCKET cli_socket;cli_socket = socket(PF_INET, SOCK_STREAM, 0);if(cli_socket == INVALID_SOCKET){printf("cli_socket init error!\n");return 0;}//4、初始化结构体SOCKADDR_IN ser_addr;//服务器IP和端口等信息memset(ser_addr, 0, sizeof(ser_addr));ser_addr.sin_family = AF_INET;ser_addr.sin_addr.s_addr = inet_addr("192.168.1.110");//指定服务器IPser_addr.sin_port = htons(8888);//指定服务器端口int ser_addrLen = sizeof(ser_addr);//5、与服务器建立连接if(connect(cli_socket, (SOCKADDR*)&ser_addr, ser_addrLen) == SOCKET_ERROR){printf("connect init error!\n");return 0;}//6、接收发送信息int recvlen = 0; //接收字节长度//可添加循环退出标志 bool flag = true;while(1){//可添加循环判断/*if(!flag){break;}*/memset(recvbuff, 0, sizeof(recvbuff));//先清空recvlen = recv(cli_socket, recvbuff, sizeof(recvbuff)-1, 0);if(recvlen > 0){ printf("recvbuff is %s\n",recvbuff);//发送数据到服务器if(send(cli_socket, buff, sizeof(buff), 0) == SOCKET_ERROR){printf("socket send information error!\n");return 0;}//flag = false;}}closesocket(cli_socket);//关闭套接字WSACleanup();//清除WSAreturn 0;
}
二、Windows网络通信服务端创建示例
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>int main()
{char buff[100] = "hello, I am Server";char recvbuff[1024] = {0};//接收信息//1、初始化WSADATA结构体对象WSADATA wsaData;//2、初始化WSAStartupif(WSAStartup(MAKEWORD(2,2), &wsaData) != 0){printf("WSAStartup init error!\n");return 0;}//3、初始化套接字 TCP套接字SOCK_STREAM,PF_INET:IPV4互联网协议族SOCKET ser_socket;//服务器监听套接字ser_socket = socket(PF_INET, SOCK_STREAM, 0);if(ser_socket == INVALID_SOCKET){printf("ser_socket init error!\n");return 0;}//4、初始化结构体SOCKADDR_IN ser_addr;//服务器IP和端口等信息memset(&ser_addr, 0, sizeof(ser_addr));ser_addr.sin_family = AF_INET;ser_addr.sin_addr.s_addr = INADDR_ANY;//指定服务器IPser_addr.sin_port = htons(8888);//指定服务器端口int ser_addrLen = sizeof(ser_addr);//5、绑定自身端口和IP信息if(bind(ser_socket, (SOCKADDR*)&ser_addr, ser_addrLen) == SOCKET_ERROR){printf("bind init error!\n");return 0;}//6、监听连接对象if(listen(ser_socket, 5) == SOCKET_ERROR){printf("Listen init error!\n");return 0;}//7、接收连接请求建立连接SOCKET cli_socket;//客户端通信套接字SOCKADDR_IN cli_addr;//客户端IP和端口等信息int cli_addrLen = sizeof(cli_addr);cli_socket = accept(ser_socket, (SOCKADDR*)&cli_addr, &cli_addrLen);if(cli_socket == INVALID_SOCKET){printf("accept client error!\n");return 0;}//8、发送信息,接收信息send(cli_socket, buff, sizeof(buff), 0);int recvNum = 0;while(1){memset(recvbuff, 0, sizeof(recvbuff));recvNum = recv(cli_socket, recvbuff, sizeof(recvbuff)-1, 0);if(recvNum > 0){ printf("recvbuff is %s\n",recvbuff);// 添加退出条件示例if(strcmp(recvbuff, "exit") == 0) break;} }closesocket(cli_socket);//关闭套接字closesocket(ser_socket);//关闭套接字WSACleanup();//清除WSAreturn 0;
}
三、服务器部分添加多线程实现
// 使用多线程或select()处理多个客户端
while(1) {SOCKET new_client = accept(...);CreateThread(NULL, 0, ClientHandler, (LPVOID)new_client, 0, NULL);
}