c语言select 写集有什么作用

fdsafwagdagadg6576 2014-09-16 03:58:11
count=select(max_fd+1,&rfd,NULL,NULL,&timeout);
select都是检测读集,写集为NULL,
从读集中read sockfd后,wirte sockfd即可通信。

请问写集有什么用呢。能不能举一个必须读写集都有,or只有写集(读集不能替代)的例子

求code
...全文
345 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
luotuo44 2014-09-17
  • 打赏
  • 举报
回复
考虑这样一个情景:一个客户端sockfd被设置成非阻塞了,现在它要connect服务器,因为非阻塞,所以它可能没有连接上服务器就返回了。那么之后怎么判断这个sockfd连上了服务器呢? 此时可把这个sockfd放到select的写集中,监听这个sockfd是否可写。如果从select返回了,那么该sockfd就可能连接上了,因为变成可写了。当然也有可能是发生了错误。所以还需要用getsockopt函数做进一步的判断。 代码就不出给了。谷歌一下“非阻塞connect”, 代码一大堆
bsnry 2014-09-17
  • 打赏
  • 举报
回复
引用 5 楼 luotuo44 的回复:
考虑这样一个情景:一个客户端sockfd被设置成非阻塞了,现在它要connect服务器,因为非阻塞,所以它可能没有连接上服务器就返回了。那么之后怎么判断这个sockfd连上了服务器呢? 此时可把这个sockfd放到select的写集中,监听这个sockfd是否可写。如果从select返回了,那么该sockfd就可能连接上了,因为变成可写了。当然也有可能是发生了错误。所以还需要用getsockopt函数做进一步的判断。 代码就不出给了。谷歌一下“非阻塞connect”, 代码一大堆
windows linux都有这种用法 没感觉出什么优势来, select + 非堵塞 ,增加代码复杂性, 因为你的判断条件更多了。 select+ 堵塞 用起来方便。 select本来就是为了解决 堵塞套接字的某些函数 堵塞 线程的问题而出现。
bsnry 2014-09-16
  • 打赏
  • 举报
回复
引用 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。
bsnry 2014-09-16
  • 打赏
  • 举报
回复
引用 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种模式: 堵塞,非堵塞。
mymtom 2014-09-16
  • 打赏
  • 举报
回复
当接收方缓冲区和发送方缓冲区都满的时候,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;
}
赵4老师 2014-09-16
  • 打赏
  • 举报
回复
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;
}

69,377

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧