目录
- 基于Select模型的通信仿真--win32编程代码
- 编程环境
- 服务端
- 客户端
基于Select模型的通信仿真--win32编程代码
编程环境
Visual C++ 6.0
服务端
#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{AllocConsole();freopen("CONOUT$","w",stdout);freopen("CONIN$", "r", stdin);freopen("CONOUT$", "w", stderr);// 初始化 WinsockWSADATA wsaData;int result=WSAStartup(MAKEWORD(2, 2), &wsaData);if (result != 0) {printf("WSAStartup failed with error: %d\n", result);return 1;}//1.创建socket套接字/*SOCKET socket(_In_ int af, //协议地址簇 IPv4:AF_INET/IPv6:AF_INET6_In_ int type, //类型 流式协议:SOCK_STREAM/数据报协议:SOCK_DGRAM_In_ int protocol //保护协议 上层协议tcp、udp不用写,填0即可);*/SOCKET listen_socket=socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET==listen_socket){printf("create listen socket failed!!! errcode: %d\n", GetLastError());WSACleanup();return -1;}//2.给socket绑定端口号/** ip地址结构体struct sockaddr_in {ADDRESS_FAMILY sin_family; //协议地址簇USHORT sin_port; //端口号 2字节IN_ADDR sin_addr; //ip地址 4字节CHAR sin_zero[8]; //保留字节 8字节};struct sockaddr {u_short sa_family; //协议地址簇CHAR sa_data[14]; //14字节}*/struct sockaddr_in local = {0};local.sin_family = AF_INET;local.sin_port = htons(8080);//绑定端口 大小端转化:中间设备使用大端序(路由器),但是电脑使用的是小端序,所以要转化/*电脑上有多个网卡,服务器可以选择接收哪个或哪些网卡传过来的数据。如:127.0.0.1(本地环回),则服务器只能和自己通信 INADDR_LOOPBACK一般写全0地址(0.0.0.0),表示接收全部网卡的数据 INADDR_ANY*///local.sin_addr.s_addr = htonl(INADDR_ANY);//接收全部网卡的数据 大小端转化local.sin_addr.s_addr = inet_addr("0.0.0.0");//接收全部网卡的数据 字符串ip转成整数ip/*int bind(SOCKET s, //绑定的套接字const struct sockaddr FAR * name, //ip地址结构体int namelen //ip地址结构体的长度);*/bind(listen_socket,(struct sockaddr*)&local,sizeof(local));//3.给socke开启监听属性,只用来接收连接/*int listen(_In_ SOCKET s, //监听套接字_In_ int backlog //);*/if (-1 == listen(listen_socket, 10)){printf("start listen failed!!! errcode: %d\n", GetLastError());WSACleanup();return -1;}fd_set redset;//4、初始化文件描述符集合 FD_ZERO(&redset);//5、添加要检测的监听文件描述符 FD_SET(listen_socket,&redset);printf("This is SERVER!\n");while (1){fd_set tmp = redset;/* 6、不停地检测文件描述符6.1 超时 select() = 0 再次检测或关闭套接字6.2 异常 select() = -1 异常处理6.3 成功 selct() >0*/printf("selecting...\n");int ret = select(-1, &tmp, NULL, NULL, NULL);if (ret <= 0){printf("select failed!!! errcode: %d\n", GetLastError());closesocket(listen_socket);WSACleanup();return -1;}// printf("select = %d\n",ret);//7、判断文件描述符属于哪一类//通过将原来redset集合中的文件描述符与select处理过的tmp集合比较,判断哪些文件描述符就绪,如果就绪,是哪一类for (int i = 0; i < (int)redset.fd_count; i++){if (FD_ISSET(redset.fd_array[i], &tmp))//判断文件描述符(套接字)i的读缓冲区是否有数据{//就绪文件描述符是监听描述符if (redset.fd_array[i] == listen_socket) // 监听套接字接收到新连接{if (redset.fd_count < FD_SETSIZE){sockaddr_in addrRemote;int nAddrLen = sizeof(addrRemote);//接收客户端的连接请求SOCKET client_socket = ::accept(listen_socket, (SOCKADDR*)&addrRemote, &nAddrLen);FD_SET(client_socket, &redset);printf("与主机 %s 建立连接\n", inet_ntoa(addrRemote.sin_addr));}else{printf("Too much connections!\n");continue;}}else//就绪文件描述符不是监听描述符,是通信描述符{//接收信息char rbuffer[1024] = { 0 };int len = recv(redset.fd_array[i], rbuffer, 1024, 0);if (len <= 0){printf("The client %d has disconnected.\n", i);FD_CLR(redset.fd_array[i], &redset);shutdown(redset.fd_array[i], SD_BOTH);closesocket(redset.fd_array[i]);break;}printf("recive from client%d:\t%s\n", i, rbuffer);//发送信息char sbuffer[1024] = { 0 };// 检查接收到的消息if (strcmp(rbuffer, "计算从1到100的奇数和") == 0){int sum = 0;for (int j = 1; j <= 100; j += 2){sum += j;}printf("send to client%d:\t1到100的奇数和是 %d\n", i, sum);sprintf(sbuffer, "1到100的奇数和是 %d\n", sum);}else{printf("send to client%d:\tunknow!\n", i);sprintf(sbuffer, "unknow!");}len = send(redset.fd_array[i], sbuffer, strlen(sbuffer), 0);if (len == -1){perror("send error");exit(1);}}}}}closesocket(listen_socket);FreeConsole();// 清理 WinsockWSACleanup();return 0;
}
客户端
#include<stdio.h>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{AllocConsole();freopen("CONOUT$","w",stdout);freopen("CONIN$", "r", stdin);freopen("CONOUT$", "w", stderr);// 初始化 WinsockWSADATA wsaData;int result=WSAStartup(MAKEWORD(2, 2), &wsaData);if (result != 0) {printf("WSAStartup failed with error: %d\n", result);return 1;}//1.创建socket套接字SOCKET client_socket = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == client_socket){printf("create socket failed!!! errcode: %d\n", GetLastError());WSACleanup();return -1;}//2.连接服务器struct sockaddr_in target;//目标服务器的ip结构体target.sin_family = AF_INET;target.sin_port = htons(8080);target.sin_addr.s_addr = inet_addr("127.0.0.1");if (-1 == connect(client_socket, (struct sockaddr*)&target, sizeof(target))){printf("connect server failed!!!\n");shutdown(client_socket, SD_BOTH);closesocket(client_socket);WSACleanup();return -1;}//3.开始通讯printf("This is Cilent1.\n\n");while (1){//发送信息printf("send:\t");char sbuffer[1024] = { 0 };scanf("%s", sbuffer);send(client_socket, sbuffer, strlen(sbuffer),0);//接收消息char rbuffer[1024] = { 0 };int ret=recv(client_socket, rbuffer, 1024, 0);if (ret <= 0){break;//断开连接}printf("recive:\t%s\n", rbuffer);}//4.关闭连接shutdown(client_socket, SD_BOTH);shutdown(client_socket, SD_BOTH);closesocket(client_socket);FreeConsole();// 清理 WinsockWSACleanup();return 0;
}