简单的 winsock select模式
2016-04-03 19:22
405 查看
// 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 1024 using 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; } // 只处理是可读状态的socket DWORD 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 6666 void 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)); } } else return; }
相关文章推荐
- 反转一个字符串的算法
- 并发编程之基础( 五)
- C++命名规范
- 深度学习核心技术
- android的Services生命周期和使用方法
- C++命名规范
- 单例模式之 懒汉模式普通版
- C#中OnLoad事件和Form1_Load事件的区别
- 导入dmp文件,提示不是有效的导出文件,头部验证失败
- tomcat服务器部署项目问题
- 如何线程安全地遍历List:Vector、CopyOnWriteArrayList
- Mac 键盘快捷键,苹果Macbook电脑快捷键
- cocos2dx 3.1从零学习(一)——入门篇(一天学会打飞机)
- Java [Leetcode 96]Unique Binary Search Trees
- RxJava-变换操作
- javaweb-国际化
- 【枚举】Vijos P1012 清帝之惑之雍正
- Android view中invalidate方法学习小节
- win8.1 如何查看com端口号
- Servlet监听器