Linux select函数问题 调用close关闭socket时,select并不会退出等待

最近在编写Linux下 视频代理服务器时,碰到了一个很奇葩的问题,现在说出来希望能有个人帮我解答。

首先,环境是centOS系统,socket用的是select模式。阻塞和非阻塞、I/O复用不复用都会出现这个问题。

当socket进入select时,另一个线程调用close关掉该socket,select不能退出等待并返回。

代码是从项目中抽出来并经过实验的,会出现这个问题没错。

代码如下:

#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>

int proxysvr_sock;

//设置非阻塞
static int SetNonBlocking(int sock)
{
  int opts;
  opts=fcntl(sock, F_GETFL, 0);

  if(opts<0)
  {
	return -1;
  }

  opts = opts | O_NONBLOCK;

  if(fcntl(sock,F_SETFL,opts)<0)
  {
	return -1;
  }
}

static void *AcceptConnectionsThread(void *arg)
{
	struct sockaddr_in sin;  /* bind socket address */
	socklen_t   sinlen;     /* length of address */

	fd_set  readfds;
	fd_set  errofds;
	int     ret, sock;
	struct timeval timeo;

	while (1)
	{
		FD_ZERO(&readfds);
		FD_SET(proxysvr_sock, &readfds);
		FD_ZERO(&errofds);
		FD_SET(proxysvr_sock, &errofds);

		timeo.tv_sec = 5;
		timeo.tv_usec = 0;

		ret = select(proxysvr_sock + 1, &readfds, (fd_set *)0, &errofds, NULL);
		printf("ret = %d\n", ret);
		if (ret == 0)
			continue;
		else if (ret < 0)
			break;

		if (FD_ISSET(proxysvr_sock, &errofds))
		{
			printf("exit ok!\n");
			break;
		}

		sinlen = sizeof(sin);
		if (FD_ISSET(proxysvr_sock, &readfds))
		{
			printf("read ok!\n");
			if ((sock = accept(proxysvr_sock, (struct sockaddr *)&sin, &sinlen)) < 0)
			{
				break;
			}
		}
	}

	return NULL;
}

int socket_create_listen(int port, int reuse, int backlog)
{
	int fd;
	struct sockaddr_in addr;

	fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (fd < 0)
	{
		return -1;
	}

	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(int)) < 0)
	{
		printf("setsockopt SO_REUSEADDR error\n");
	}

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(port);
	if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
	{
		close(fd);
		return -1;
	}

    SetNonBlocking(fd);//把客户端的socketFD设置为非阻塞
	if (listen(fd, backlog) < 0)
	{
		close(fd);
		return -1;
	}
	return fd;
}

int main()
{
	int ret;
	int port = 9990;
	pthread_t rtspd_tid;

	proxysvr_sock = socket_create_listen(port, 1, 100);
	if (proxysvr_sock < 0)
		return -1;

	if ((ret = pthread_create(&rtspd_tid, NULL, AcceptConnectionsThread, (void *)NULL)) != 0)
	{
		close(proxysvr_sock);
		proxysvr_sock = -1;
		return -1;
	}
	while(1)
	{
		printf("wait for input...\n");
		char c = getchar();
		printf("c=%c\n", c);
		if(c=='q')
			break;
	}
	ret = close(proxysvr_sock);
	printf("Ret = %d\n", ret);
	if (ret != 0)
	{
		printf("socket close %d error\r\n", proxysvr_sock);
	}
	printf("ProxyServer_Uninitialize socket close %d\r\n", proxysvr_sock);
	pthread_join(rtspd_tid, 0);
	proxysvr_sock = -1;

	return 0;
}

希望能有高手解答。先谢过了

感谢大神“帅得不敢出门”(ID:zmlovelx)慷慨解答,问题答案就在man帮助里面

Multithreaded applications If a file descriptor being monitored by select() is closed in another thread, the result is unspecified. On some UNIX systems, select() unblocks and returns, with an indication that the file descriptor is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned and the I/O operations was performed). On Linux (and some other systems), closing the file descriptor in another thread has no effect on select(). In summary, any application that relies on a particular behavior in this scenario must be considered buggy.

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值