简单的 winsock select模式

来源:互联网 发布:鬼吹灯怎么样 知乎 编辑:程序博客网 时间:2024/05/16 11:46
// WinSelectModel.cpp : 定义控制台应用程序的入口点。////server side ,select model/*Syntax: int select(_In_    int                  nfds,//Ignored. The nfds parameter is included only for compatibility with Berkeley sockets._Inout_ fd_set               *readfds,//An optional pointer to a set of sockets to be checked for readability._Inout_ fd_set               *writefds,//An optional pointer to a set of sockets to be checked for writability._Inout_ fd_set               *exceptfds,//An optional pointer to a set of sockets to be checked for errors._In_    const struct timeval *timeout//The maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.)功能:简单的讲就是一个socket“复用器”(不必为第个客户建立新线程,但需要不断轮询fd_set检测,fd_set的大小固定64),它能够检测报告一个或多个socket状态 ,但不如WSAASyncSelct()那么细致,第次调用,select ()把一组socket作为输入参数,而且它是阻塞的(可设置),也就是说该函数能使你同时检测多个socket的状态,它需要通过返回值来带回执行结果Return value:成功返回当前状态与设定状态相匹配的socket的总数,超时返回0(timeout参数),失败返回SOCKET_ERROR remarks:它与BSD兼容 ,也可以使用WSAAsyncSelect() ,timeout非零则阻塞,零则不阻塞(但不要传NULL为无限阻塞)应用:网络连接数不大的程序 与select配合使用的宏FD_ZERO(*set) :对fd_set初始化FD_SET(s, *set):添加指定s套接字至集合FD_CLR(s, *set):删除指定s套接字至集合FD_ISSET(s, *set):检查指定s套接字是否集合FD_SETSIZE: 64 */#include "stdafx.h"#include<iostream>#include<WinSock2.h>                    // socket 所需要的头文件#pragma comment(lib,"WS2_32.lib")// link socket 库#define PORT 6666 #define BUFLEN 1024using namespace std;fd_set g_fdClientSocket;//fd_set DWORD WINAPI ThreadProc(LPVOID lpParameter);int main(){DWORD dwThreadID;sockaddr_in addrClient;int addrClientLen = sizeof(addrClient);SOCKET sServer = INVALID_SOCKET;SOCKET sClient;int nClientCount = 0;// 1 启动并初始化winsock(WSAStarup)WSADATA wsaData;if (WSAStartup(0x202, &wsaData))//成功返回0{return FALSE;}//2 创建套接字(socket) sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == sServer){WSACleanup();return FALSE;}//3 准备通信地址SOCKADDR_IN addrServer;addrServer.sin_family = AF_INET;addrServer.sin_port = htons(PORT);//服务器用于监听的端口号,客户端需要知道这个端口进行连接addrServer.sin_addr.s_addr =  INADDR_ANY;//4 绑定地址与socket(bind)if (SOCKET_ERROR == bind(sServer, (const sockaddr*)&addrServer, sizeof(SOCKADDR_IN))){closesocket(sServer);WSACleanup();return FALSE;}//5 监听 (listen)if (SOCKET_ERROR == listen(sServer, SOMAXCONN)){closesocket(sServer);WSACleanup();}//6 线程利用select()处理可读的客户端CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwThreadID);// 7 等待多个客户端连接(accpet)while (nClientCount<FD_SETSIZE) { sClient= accept(sServer, (sockaddr *)&addrClient, &addrClientLen);if (INVALID_SOCKET == sClient){cout << WSAGetLastError() << endl;//或根据错误码进行其他操作closesocket(sServer);closesocket(sClient);WSACleanup();return FALSE;}printf("Accepted client:%s:%d\n", inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));FD_SET(sClient,& g_fdClientSocket);nClientCount++;}system("pause");return TRUE;}// 只处理是可读状态的socketDWORD WINAPI ThreadProc(LPVOID lpParameter){fd_set fdRead;fd_set fdWrite;FD_ZERO(&fdRead);FD_ZERO(&fdWrite);int nRet = 0;char recvBuffer[1024] = {};struct timeval stTimeOut = { 1,0 };while (true){fdRead = g_fdClientSocket;fdWrite = g_fdClientSocket;nRet = select(0, &fdRead, &fdWrite, NULL, &stTimeOut); if (SOCKET_ERROR != nRet){for (int i = 0; i < g_fdClientSocket.fd_count; i++){if (FD_ISSET(g_fdClientSocket.fd_array[i], &fdRead)){memset(recvBuffer, 0, sizeof(recvBuffer));SOCKADDR_IN stAddrTemp;int nTempLen = sizeof(stAddrTemp);nRet = recvfrom(g_fdClientSocket.fd_array[i], recvBuffer, sizeof(recvBuffer), 0, (sockaddr*)&stAddrTemp, &nTempLen);if (SOCKET_ERROR == nRet){closesocket(g_fdClientSocket.fd_array[i]);FD_CLR(g_fdClientSocket.fd_array[i], &g_fdClientSocket);}else{cout << "the client(" << inet_ntoa(stAddrTemp.sin_addr) << ":" << ntohs(stAddrTemp.sin_port) << ") :" << recvBuffer << "(message size is " << nTempLen << ")" << endl;}}if (FD_ISSET(g_fdClientSocket.fd_array[i], &fdWrite)){nRet = send(g_fdClientSocket.fd_array[i], "hello Client", sizeof("hello Client"), 0);if (SOCKET_ERROR == nRet){int nErrorNo = WSAGetLastError();cout << "send error code is " << nErrorNo << endl;//10038  socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.closesocket(g_fdClientSocket.fd_array[i]);FD_CLR(g_fdClientSocket.fd_array[i], &g_fdClientSocket);}else{continue;}}}}}}

// WinSelectClient.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include<WinSock2.h>//客户端 #include<iostream>#pragma comment(lib,"WS2_32.lib")using namespace std;#define BUFLEN 1024#define PORT 6666void getIP(char*szHostaddress);void SendProc();SOCKET sHost;int main(){WSADATA wsaData;// 1 启动并初始化winsock(WSAStarup)if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0{return FALSE;}//2 创建套接字(socket)sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == sHost){closesocket(sHost);WSACleanup();return FALSE;}//3 准备通信地址char szHostaddress[200];getIP(szHostaddress);SOCKADDR_IN addrServer;addrServer.sin_family = AF_INET;addrServer.sin_port = htons(PORT);addrServer.sin_addr.s_addr = inet_addr(szHostaddress);//4 连接服务器(connect)if (SOCKET_ERROR == connect(sHost, (const sockaddr*)&addrServer, sizeof(addrServer)))//连接到指定的地址{closesocket(sHost);WSACleanup();return FALSE;}//5 发送数据 (send)char sendBuf[BUFLEN] = "你好服务器!";if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0)){closesocket(sHost);WSACleanup();return FALSE;}cout << "客户端发送消息成功!" << endl;//7 接收数据(recv)char recvBuf[BUFLEN];ZeroMemory(recvBuf, sizeof(recvBuf));if (SOCKET_ERROR == recv(sHost, recvBuf, sizeof(recvBuf), 0)){closesocket(sHost);WSACleanup();return FALSE;}cout << "服务器发来的消息:" << recvBuf << endl;while (true){SendProc();Sleep(1000);}system("pause");}void SendProc(){char sendBuf[BUFLEN] = "你好服务器!";if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0)){closesocket(sHost);WSACleanup();return ;}cout << "客户端发送消息成功!" << endl;}void getIP(char*szHostaddress) {char szHostname[100];if (gethostname(szHostname, sizeof(szHostname)) != SOCKET_ERROR)//先得到主机名{HOSTENT *pHostEnt = gethostbyname(szHostname);//通过名字拿到地址if (pHostEnt != NULL){sprintf(szHostaddress, "%d.%d.%d.%d",(pHostEnt->h_addr_list[0][0] & 0x00ff),(pHostEnt->h_addr_list[0][1] & 0x00ff),(pHostEnt->h_addr_list[0][2] & 0x00ff),(pHostEnt->h_addr_list[0][3] & 0x00ff));}}elsereturn;}

0 0
原创粉丝点击