user-0 提问: socket通信中可以用select函数来解决单线程问题吗？

回复:
user: user-0
content: 多谢各位啦~

user: user-1
content: 引用 10 楼 yulihua49 的回复:[quote=引用 9 楼 q191201771 的回复:] 看需求咯 如果是linux一般一个epoll线程够了 无论select或epoll，在一个线程时，都可以理解为一个线程的线程池。 多线程时，epoll比较方便实现，select比较麻烦，而且低效。[/quote] 撇开效率，上层写代码，epoll和select其实差不多，都是每个socket都是由一且唯一的epoll（select）管理 你说的一个线程相当于线程池中的一个线程，其实还是有差别的，你可以考虑下多对多通信的情况，就要跨线程了。 另外，如果计算比较密集，把计算和io线程分离也行。 这里我写的一个epoll库 https://code.csdn.net/q191201771/chef

user: user-2
content: 可以系统的看看APUE

user: user-1
content: 看需求咯 如果是linux一般一个epoll线程够了

user: user-3
content: 参考MSDN98\SAMPLES\VC98\SDK\NETDS\WINSOCK\SIMPLE\IOCTL.C /******************************************************************************\ * ioctl.c - TCP server * *       This is a part of the Microsoft Source Code Samples. *       Copyright 1996-1997 Microsoft Corporation. *       All rights reserved. *       This source code is only intended as a supplement to *       Microsoft Development Tools and/or WinHelp documentation. *       See these sources for detailed information regarding the *       Microsoft samples programs. \******************************************************************************/    #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <stdlib.h> #include <stdio.h> #include <string.h>  #define DEFAULT_PORT 5001  int ReadAndEcho(SOCKET , char *,int ) ; int WriteMessage(SOCKET , char *,int ) ;  void Usage(char *progname) {     fprintf(stderr,"Usage\n%s -e [endpoint] -i [interface]\n",         progname);     fprintf(stderr,"Where:\n");     fprintf(stderr,"\tendpoint is the port to listen on\n");     fprintf(stderr,"\tinterface is the ipaddr (in dotted decimal notation)");     fprintf(stderr," to bind to\n");     fprintf(stderr,"Defaults are 5001 and INADDR_ANY\n");     WSACleanup();     exit(1); } int main(int argc, char **argv) {      char Buffer[128];     char *interface= NULL;     unsigned short port=DEFAULT_PORT;     int fromlen;     int i, ioctl_opt =1;     struct sockaddr_in local, from;     WSADATA wsaData;     SOCKET listen_socket, msgsock;     fd_set readfds, writefds, exceptfds;      /* Parse arguments */     if (argc >1) {         for(i=1;i <argc;i++) {             if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {                 switch(tolower(argv[i][1])) {                     case 'i':                         interface = argv[++i];                         break;                     case 'e':                         port = atoi(argv[++i]);                         break;                     default:                         Usage(argv[0]);                         break;                 }             }             else                 Usage(argv[0]);         }     }      if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {         fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());         WSACleanup();         return -1;     }      if (port == 0){         Usage(argv[0]);     }      //     // The fd sets should be zeroed out before using them to prevent errors.     FD_ZERO(&readfds);     FD_ZERO(&writefds);     FD_ZERO(&exceptfds);     memset(Buffer,0,sizeof(Buffer));      local.sin_family = AF_INET;      //     // bind to specific interface if desired.      local.sin_addr.s_addr = (!interface)?INADDR_ANY:inet_addr(interface);      /*      * Port MUST be in Network Byte Order      */     local.sin_port = htons(port);      listen_socket = socket(AF_INET, SOCK_STREAM,0); // TCP socket     if (listen_socket == INVALID_SOCKET){         fprintf(stderr,"socket() failed with error %d\n",WSAGetLastError());         WSACleanup();         return -1;     }     //     // bind() associates a local address and port combination with the     // socket just created.      if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) )         == SOCKET_ERROR) {         fprintf(stderr,"bind() failed with error %d\n",WSAGetLastError());         WSACleanup();         return -1;     }      //     // start listening on the socket for incoming connections     //     if (listen(listen_socket,5) == SOCKET_ERROR) {         fprintf(stderr,"listen() failed with error %d\n",WSAGetLastError());         WSACleanup();         return -1;     }     printf("%s: Listening on port %d\n",argv[0],port);      //     // Set the socket to non-blocking mode.     //     if (ioctlsocket(listen_socket,FIONBIO,&ioctl_opt) == SOCKET_ERROR) {         fprintf(stderr,"ioctlsocket failed %d\n",WSAGetLastError());         WSACleanup();         return -1;     }     //     // The structure of the loop below is very simple. We only accept one     // connection at a time. As soon as another client connects, we     // disconnect the first one, and start talking to the new client.     // All this server does is to echo the data received on the socket     // back to the client.     //     // This is not a very realistic server, but it does serve to show that     // select() does not scale very well on win32. If we were dealing     // with more than one client, we would have to have a list of sockets     // that are in each fdset to be able to check them when select()     // returns.     //     while(1) {          //         // A socket in the listen() state becomes ready to read when a         // client connects to it. An accept() will complete without         // blocking.         // Since select sets the sockets that are ready to be read from or         // written to, we have to include listen_socket in the fdset each time         // through the loop.         //          FD_SET(listen_socket,&readfds);          i = select(0,&readfds,&writefds,&exceptfds,NULL);         if (i == SOCKET_ERROR) {             fprintf(stderr,"select failed %d\n",WSAGetLastError());         }         if (i==0){             fprintf(stderr,"Select returned no fds ready\n");         }          if (FD_ISSET(listen_socket, &readfds)){             //             // close the previous client socket.             // We must also clear it from the fdset to prevent select()             // from failing.             //             closesocket(msgsock);             FD_CLR(msgsock,&readfds);             FD_CLR(msgsock,&writefds);             fromlen = sizeof(from);             msgsock= accept(listen_socket,(struct sockaddr*)&from,&fromlen);             if (msgsock == INVALID_SOCKET) {                 fprintf(stderr,"accept failed %d\n",WSAGetLastError());                 WSACleanup();                 return -1;             }             FD_SET(msgsock,&writefds);             FD_SET(msgsock,&readfds);             continue;         }         if (FD_ISSET(msgsock,&readfds) ) {             //             // socket is ready to read, i.e., there is data on the socket.             //             if (ReadAndEcho(msgsock,Buffer,sizeof(Buffer))<0) {                 fprintf(stderr,"terminating connection\n");                 FD_CLR(msgsock,&readfds);                 FD_CLR(msgsock,&writefds);                 closesocket(msgsock);                 continue;             }         }         if (FD_ISSET(msgsock,&writefds) ){             if (WriteMessage(msgsock,Buffer,sizeof(Buffer)) <=0) {                 fprintf(stderr,"terminating connection\n");                 FD_CLR(msgsock,&readfds);                 FD_CLR(msgsock,&writefds);                 closesocket(msgsock);                 continue;             }         }         FD_SET(msgsock,&writefds);         FD_SET(msgsock,&readfds);     } } int ReadAndEcho(SOCKET insock, char *Buffer,int size) {     int rc;      rc = recv(insock,Buffer,size,0);      if (rc == SOCKET_ERROR) {         fprintf(stderr,"recv() failed with error %d\n",WSAGetLastError());         return -1;     }     if (rc ==0) {         fprintf(stderr,"Connection closed by client\n");         return 0;     }     printf("Received [%s] from client\n",Buffer);     return rc; } int WriteMessage(SOCKET outsock, char *Buffer,int size) {     int rc;     int lasterr;      printf("Sending [%s] to client\n",Buffer);     rc = send(outsock,Buffer,size, 0);      if (rc == SOCKET_ERROR) {       lasterr = WSAGetLastError();       if (lasterr == WSAEWOULDBLOCK)         return 0;       else {         fprintf(stderr,"send() failed with error %d\n",lasterr);         return -1;       }     }     if (rc ==0) {         fprintf(stderr,"Connection closed by client\n");     }     return rc; }  http://bbs.csdn.net/topics/390374955

user: user-4
content: 只是不阻塞而已！客户端的请求处理还是得排队。。

user: user-5
content: 可以实现，UNP V1 149页里面有具体的实现方法。但是通常我不会这么做。

user: user-6
content: 引用 2 楼 user-11 的回复:单线程用select可以实现多链接，可是和多线程比，有毛优势呢。 没啥优势，只是select实现多线程很麻烦，一般就不费那个劲了。

user: user-6
content: 引用 9 楼 q191201771 的回复:看需求咯 如果是linux一般一个epoll线程够了 无论select或epoll，在一个线程时，都可以理解为一个线程的线程池。 多线程时，epoll比较方便实现，select比较麻烦，而且低效。

user: user-7
content: select函数只能解决小连接数量的socket连接，一般默认定义小于64个。多的还是使用多线程比较好。参考《windows网络和通信程序设计》第一章

user: user-8
content: 引用 6 楼 sd530842780 的回复:这个只是一种方法吧，相当于做了一个小玩具 同意

user: user-9
content: 这个只是一种方法吧，相当于做了一个小玩具

user: user-10
content: 引用 3 楼 galileo_chan 的回复:引用 2 楼 user-11 的回复:单线程用select可以实现多链接，可是和多线程比，有毛优势呢。确实没有什么优势，只能说是在单线程下一种实现方法吧。。 select函数的例子可以看《UNIX网络编程（卷1）》。 有没有优势看具体的需求。考虑一下IO密集型和CPU密集型两种需求

user: user-0
content: 引用 2 楼 user-11 的回复:单线程用select可以实现多链接，可是和多线程比，有毛优势呢。确实没有什么优势，只能说是在单线程下一种实现方法吧。。

user: user-11
content: 单线程用select可以实现多链接，可是和多线程比，有毛优势呢。

user: user-0
content: #define MAX_SOCK_FD  FD_SETSIZE #define BUFFER_SIZE  1024  #include"MyMsg.h"  #define PORT 6000									//服务器端口地址 #define MAX_MANY_CLIENT  255			//最多可接收的客户端数 #define IP	"127.0.0.1"		    		//服务器IP地址  int serverSocketFd = 0;			    	//服务器的socket的文件描述符 int clientSocketFd = 0;  struct sockaddr_in server_addr = {0} ;	//用于聆听客户端的socket描述符，并放于等待队列中 struct sockaddr_in client_addr = {0} ; socklen_t  socklen = sizeof(struct sockaddr_in);  void startCommunication(FILE*fp,char*fm,manInfolinkT*p1 ,onLineManInfolinkT *p2) { 	int fd	; 	 	int  i = 0;    //用于循环 	int  j = 0;	   //存放某个字符所在的位置 	int  m = 0;    //用于循环计数 	int bai = 0;   //暂存fd的百位 	int shi = 0;   //暂存fd的个十位 	int ge  = 0;   //暂存fd的个位 	int flag = 0;  //用存储数据包标志 	int privateCode = 0 ;//存放要发送给谁的fd 	 	manInfoT  manInfo = { 0 };// 存放已经报文中解析的数据 	onLineManInfoT  onLineManInfo = {0} ; //暂存登录报文中在线人员的信息 	onLineManNodeT  *pOnLineManNodeTemp = NULL;  // 用于遍历在线人员 	char *passWordTemp;	      //暂存找到的找到该昵称所对应的密码 	int recSize = 0;          //接收的字节数 	 	int result = 0;		        //函数返回值，用户判断函数是否成功被调用 	char buf[BUFFER_SIZE];		 	fd_set inset, temp_inset;  	 	signal(SIGPIPE, SIG_IGN);  	createSocket(&serverSocketFd )	; 	 	bindSocket();  	listenSocket(); 	 	FD_ZERO(&inset); 	FD_SET(serverSocketFd, &inset); 	while(1) 	{ 		temp_inset = inset;  		selectSocket(MAX_SOCK_FD,&temp_inset);// 		 		for(fd = 3; fd < MAX_SOCK_FD; fd++) 		{ 			if(FD_ISSET(fd, &temp_inset) != 0) 			{ 				if(fd == serverSocketFd) 				{ 					clientSocketFd = accept_socket()	; 					FD_SET(clientSocketFd, &inset)	; 					printf("New connection from %d(socket)\n", clientSocketFd); 				}  				else  				{		 					memset(buf, 0, sizeof(buf)); 					result = recv(fd, buf, BUFFER_SIZE, 0);                                         。。。。。。。。                                         。。。。。。。。                                         。。。。。。。。