user-0 提问: c语言select 写集有什么作用

回复:
user: user-1
content: 考虑这样一个情景：一个客户端sockfd被设置成非阻塞了，现在它要connect服务器，因为非阻塞，所以它可能没有连接上服务器就返回了。那么之后怎么判断这个sockfd连上了服务器呢？ 此时可把这个sockfd放到select的写集中，监听这个sockfd是否可写。如果从select返回了，那么该sockfd就可能连接上了，因为变成可写了。当然也有可能是发生了错误。所以还需要用getsockopt函数做进一步的判断。 代码就不出给了。谷歌一下“非阻塞connect”， 代码一大堆

user: user-2
content: 引用 5 楼 luotuo44 的回复:考虑这样一个情景：一个客户端sockfd被设置成非阻塞了，现在它要connect服务器，因为非阻塞，所以它可能没有连接上服务器就返回了。那么之后怎么判断这个sockfd连上了服务器呢？ 此时可把这个sockfd放到select的写集中，监听这个sockfd是否可写。如果从select返回了，那么该sockfd就可能连接上了，因为变成可写了。当然也有可能是发生了错误。所以还需要用getsockopt函数做进一步的判断。 代码就不出给了。谷歌一下“非阻塞connect”， 代码一大堆  windows  linux都有这种用法  没感觉出什么优势来，  select + 非堵塞 ，增加代码复杂性， 因为你的判断条件更多了。  select+ 堵塞 用起来方便。  select本来就是为了解决 堵塞套接字的某些函数 堵塞 线程的问题而出现。

user: user-2
content: 引用 2 楼 mymtom 的回复:当接收方缓冲区和发送方缓冲区都满的时候，send会阻塞的，用select可以判断到这种情况并进行处理(比如超时控制)  #include <sys/types.h> #include <sys/time.h> #include <sys/select.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>  #include <unistd.h>  #include <stdio.h> #include <string.h>  #define SERV_PORT   8000  #define info(fmt, ...)  printf("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__) int serv(void) {     int ret;     int servfd, clntfd;     struct sockaddr_in servaddr;     int optval;     ssize_t len;     char buf[1024];      servfd = socket(PF_INET, SOCK_STREAM, 0);      optval = 1;     setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));      memset(&servaddr, 0, sizeof(servaddr));     servaddr.sin_family = AF_INET;     servaddr.sin_port = htons(SERV_PORT);     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);      bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr));     listen(servfd, 5);      clntfd = accept(servfd, NULL, NULL);      for (;;) {         getchar();         memset(buf, 0, sizeof(buf));         len = recv(clntfd, buf, sizeof(buf), 0);     } }  int clnt(void) {     int ret;     int fd;     struct sockaddr_in addr;     fd_set wfds;     struct timeval tv;     int n;     ssize_t len;     char s[] = "0123456789ABCDEF";      fd = socket(PF_INET, SOCK_STREAM, 0);      memset(&addr, 0, sizeof(addr));     addr.sin_family = AF_INET;     addr.sin_port = htons(SERV_PORT);     addr.sin_addr.s_addr = inet_addr("127.0.0.1");      ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));      int count = 0;     for (;;) {         FD_ZERO(&wfds);         FD_SET(fd, &wfds);         tv.tv_sec = 10;         tv.tv_usec = 0;         /* 如果这里不进行select, 接收方缓冲区和发送方缓冲区都满的情况下send会阻塞          * 使用select可以判断这种情况, 进行相应的处理(例如超时控制) */         n = select(fd + 1, NULL, &wfds, NULL, &tv);         if (n == 0) {             info("select n=%d: %s\n", n, "timeout");             continue;         }         len = send(fd, s, strlen(s), 0);         count += len;         info("send count=%d\n", (int)count);     }      return 0; }  int main(int argc, char *argv[]) {     pid_t pid;      pid = fork();     if (pid == 0) {         (void)serv();     } else {         sleep(1);         (void)clnt();     }      return 0; }   select最神奇 地方，   fd_set后，  call  select调用，额也是会返回>1的值，这样，你就可以 直接send了了。  可惜的是，很多书籍都不讲解， 导致， 读者以为，必须先send，后select。

user: user-2
content: 引用 2 楼 mymtom 的回复:当接收方缓冲区和发送方缓冲区都满的时候，send会阻塞的，用select可以判断到这种情况并进行处理(比如超时控制)  #include <sys/types.h> #include <sys/time.h> #include <sys/select.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>  #include <unistd.h>  #include <stdio.h> #include <string.h>  #define SERV_PORT   8000  #define info(fmt, ...)  printf("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__) int serv(void) {     int ret;     int servfd, clntfd;     struct sockaddr_in servaddr;     int optval;     ssize_t len;     char buf[1024];      servfd = socket(PF_INET, SOCK_STREAM, 0);      optval = 1;     setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));      memset(&servaddr, 0, sizeof(servaddr));     servaddr.sin_family = AF_INET;     servaddr.sin_port = htons(SERV_PORT);     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);      bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr));     listen(servfd, 5);      clntfd = accept(servfd, NULL, NULL);      for (;;) {         getchar();         memset(buf, 0, sizeof(buf));         len = recv(clntfd, buf, sizeof(buf), 0);     } }  int clnt(void) {     int ret;     int fd;     struct sockaddr_in addr;     fd_set wfds;     struct timeval tv;     int n;     ssize_t len;     char s[] = "0123456789ABCDEF";      fd = socket(PF_INET, SOCK_STREAM, 0);      memset(&addr, 0, sizeof(addr));     addr.sin_family = AF_INET;     addr.sin_port = htons(SERV_PORT);     addr.sin_addr.s_addr = inet_addr("127.0.0.1");      ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));      int count = 0;     for (;;) {         FD_ZERO(&wfds);         FD_SET(fd, &wfds);         tv.tv_sec = 10;         tv.tv_usec = 0;         /* 如果这里不进行select, 接收方缓冲区和发送方缓冲区都满的情况下send会阻塞          * 使用select可以判断这种情况, 进行相应的处理(例如超时控制) */         n = select(fd + 1, NULL, &wfds, NULL, &tv);         if (n == 0) {             info("select n=%d: %s\n", n, "timeout");             continue;         }         len = send(fd, s, strlen(s), 0);         count += len;         info("send count=%d\n", (int)count);     }      return 0; }  int main(int argc, char *argv[]) {     pid_t pid;      pid = fork();     if (pid == 0) {         (void)serv();     } else {         sleep(1);         (void)clnt();     }      return 0; }    请问：   linux select的，下，会不会把套接字自动设置为 非堵塞？  套接字有2种模式： 堵塞，非堵塞。

user: user-3
content: 当接收方缓冲区和发送方缓冲区都满的时候，send会阻塞的，用select可以判断到这种情况并进行处理(比如超时控制)  #include <sys/types.h> #include <sys/time.h> #include <sys/select.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h>  #include <unistd.h>  #include <stdio.h> #include <string.h>  #define SERV_PORT   8000  #define info(fmt, ...)  printf("%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__) int serv(void) {     int ret;     int servfd, clntfd;     struct sockaddr_in servaddr;     int optval;     ssize_t len;     char buf[1024];      servfd = socket(PF_INET, SOCK_STREAM, 0);      optval = 1;     setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));      memset(&servaddr, 0, sizeof(servaddr));     servaddr.sin_family = AF_INET;     servaddr.sin_port = htons(SERV_PORT);     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);      bind(servfd, (struct sockaddr *)&servaddr, sizeof(servaddr));     listen(servfd, 5);      clntfd = accept(servfd, NULL, NULL);      for (;;) {         getchar();         memset(buf, 0, sizeof(buf));         len = recv(clntfd, buf, sizeof(buf), 0);     } }  int clnt(void) {     int ret;     int fd;     struct sockaddr_in addr;     fd_set wfds;     struct timeval tv;     int n;     ssize_t len;     char s[] = "0123456789ABCDEF";      fd = socket(PF_INET, SOCK_STREAM, 0);      memset(&addr, 0, sizeof(addr));     addr.sin_family = AF_INET;     addr.sin_port = htons(SERV_PORT);     addr.sin_addr.s_addr = inet_addr("127.0.0.1");      ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));      int count = 0;     for (;;) {         FD_ZERO(&wfds);         FD_SET(fd, &wfds);         tv.tv_sec = 10;         tv.tv_usec = 0;         /* 如果这里不进行select, 接收方缓冲区和发送方缓冲区都满的情况下send会阻塞          * 使用select可以判断这种情况, 进行相应的处理(例如超时控制) */         n = select(fd + 1, NULL, &wfds, NULL, &tv);         if (n == 0) {             info("select n=%d: %s\n", n, "timeout");             continue;         }         len = send(fd, s, strlen(s), 0);         count += len;         info("send count=%d\n", (int)count);     }      return 0; }  int main(int argc, char *argv[]) {     pid_t pid;      pid = fork();     if (pid == 0) {         (void)serv();     } else {         sleep(1);         (void)clnt();     }      return 0; }

user: user-4
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; }