标签:select模型 io socket模式 阻塞blocking 非阻塞non-blocking
场景:
1. 当使用socket通讯时,客户端或者服务端需要1对多的情况,为了维护多个连接,简单的blocking模式是
满足不了要求的,所以这时候需要简单的select I/O 模型基本能解决问题,因为它的recv和send并不是
立即返回的,所以它其实还是属于blocking模式.
非阻塞模式需要调用:
nRet = ioctlsocket(s, FIONBIO, (unsigned long *) &ul);
// socket_select_client.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <winsock2.h> #include <stdint.h> #include <windows.h> #include <iostream> using namespace std; SOCKET GetNewSocket() { SOCKET server_socket; fd_set fdread,fdwrite; int ret; // Create a socket, and accept a connection server_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if(server_socket == INVALID_SOCKET ) { return INVALID_SOCKET; } return server_socket; } int ConnectToDevice(SOCKET server_socket,uint16_t port) { struct sockaddr_in server; server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(port); int r = ::connect( server_socket, (sockaddr*)&server, sizeof(server) ); if ( r == SOCKET_ERROR ) { DWORD dwError = ::WSAGetLastError(); cout << "connect error" << endl; if ( dwError != WSAEWOULDBLOCK ) { cout << "dwError != WSAEWOULDBLOCK" << endl; closesocket(server_socket); return INVALID_SOCKET; } } cout << "connect" << endl; return 0; } DWORD WINAPI SendThread(PVOID pvParam) { cout << "SendThread" << endl; SOCKET s = *(SOCKET*)pvParam; const int kLen = 1024; char buf[kLen]; int i = 1; while(true) { cout << "i: " << i << endl; memset(buf,i,kLen); send(s,buf,kLen,0); Sleep(2000); ++i; } return 0; } void StartClient() { SOCKET s = GetNewSocket(); ConnectToDevice(s,8083); //1.启动发送线程. DWORD dwThreadID; HANDLE hThread = CreateThread(NULL,0,SendThread,(PVOID)&s,0,&dwThreadID); CloseHandle(hThread); fd_set fdread; char buffer[1024]; while(true) { FD_ZERO(&fdread); FD_SET(s, &fdread); TIMEVAL tv = {1,0}; int ret = select(0, &fdread, NULL, NULL, &tv); for(int i = 0; i< ret; ++i) { int readed = 0; //1.同server readed = recv(s,buffer,1024,0); if(readed == SOCKET_ERROR) { int code = WSAGetLastError(); cout << "code: " << code << endl; //1.socket已经断开 break; }else if(readed == 0) { // If the connection has been gracefully closed, // the return value is zero. break; }else { //1.读取数据 cout << "readed: " << readed << endl; } } } closesocket(s); } int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa); StartClient(); WSACleanup(); return 0; }
// test_socket_select.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <winsock2.h> #include <windows.h> #include <iostream> using namespace std; void StartServer() { fd_set fdread,fdwrite; SOCKET server_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); struct sockaddr_in server; server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); int value = 8083; server.sin_port = htons(value); int ret = bind(server_socket, (sockaddr*)&server, sizeof(server)); cout << "binding port..." << value << endl; if(ret == SOCKET_ERROR) { int code = WSAGetLastError(); cout << "error binding code: " << code << endl; closesocket(server_socket); return; } ret = listen(server_socket, 4); int nSize = sizeof(server); NewConn: SOCKET client_conn = accept(server_socket,( sockaddr*) &server, &nSize); char buf[64]; int buf_size = 64; getsockopt(client_conn, SOL_SOCKET,SO_MAX_MSG_SIZE,buf,&buf_size); if( client_conn == INVALID_SOCKET ) { closesocket(server_socket); return; } cout << "accept" << endl; const int kLen = 512; char buffer[kLen]; ZeroMemory(buffer, kLen); while(true) { FD_ZERO(&fdread); //1.加入fdread,如果有多个连接,也是这种方式加入fdread. //2.获取客户端连接其实是需要一个独立线程去监听的获取并加入队列的. FD_SET(client_conn, &fdread); //1.The select function returns the total number of socket handles // that are ready and contained in the fd_set structures, // zero if the time limit expired, or SOCKET_ERROR if an error occurred if ((ret = select(0, &fdread, NULL, NULL, NULL)) == SOCKET_ERROR) { closesocket(client_conn); goto NewConn; } for(int i = 0; i <ret; ++i) { //1.这里其实应该是根据i遍历fdread的,比如conns[i],而不是client_conn. //1.可以用vector来存储SOCKET.有时间的童鞋自己写吧. //1.Nonzero if s is a member of the set. Otherwise, zero. if (FD_ISSET(client_conn, &fdread)) { cout << "get fdread" << endl; int readed = 0; readed = recv(client_conn,buffer,kLen,0); if(readed == SOCKET_ERROR) { int code = WSAGetLastError(); cout << "code: " << code << endl; //1.socket已经断开 closesocket(client_conn); goto NewConn; }else if(readed == 0) { // If the connection has been gracefully closed, // the return value is zero. closesocket(client_conn); goto NewConn; }else { //1.读取数据 cout << "readed: " << readed << " :" << (int)buffer[0] << endl; //1.发数据 send(client_conn,buffer,readed,0); } } } } closesocket(server_socket); } int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa); StartServer(); WSACleanup(); return 0; }
[网络编程]_[Socket]_[Socket 阻塞模式(blocking)下的 I/O模型(model) 之 Select 模型(model)初探]
标签:select模型 io socket模式 阻塞blocking 非阻塞non-blocking
原文地址:http://blog.csdn.net/infoworld/article/details/43935853