select实现tcp并发

#include "head.h"


int init_tcp_ser(const char *ip, unsigned short port)
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("fail socket");
		return -1;
	}
	
	struct sockaddr_in ser;
	ser.sin_family = AF_INET;
	ser.sin_port = htons(port);
	ser.sin_addr.s_addr = inet_addr(ip);
	int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));
	if (-1 == ret)
	{
		perror("fail bind");
		return -1;
	}

	ret = listen(sockfd, 100);
	if (-1 == ret)
	{
		perror("fail listen");
		return -1;
	}

	return sockfd;

}

int main(int argc, const char *argv[])
{
	char buff[1024] = {0};
	struct sockaddr_in cli;
	socklen_t clilen = sizeof(cli);
	int sockfd = init_tcp_ser("192.168.1.189", 50000);
	if (-1 == sockfd)
	{
		return -1;
	}
	
	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(sockfd, &fds);
	int maxfd = sockfd;
	fd_set tmpfds;

	while (1)
	{
		tmpfds = fds;
		int cnt = select(maxfd+1, &tmpfds, NULL, NULL, NULL);
		if (cnt < 0)
		{
			perror("fail select");
			return -1;
		}

		if (FD_ISSET(sockfd, &tmpfds))
		{
			int connfd = accept(sockfd, (struct sockaddr*)&cli, &clilen);
			if (connfd < 0)
			{
				perror("fail accept");
				continue;
			}
			printf("[%s %d] getline\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port));
			FD_SET(connfd, &fds);
			maxfd = connfd > maxfd ? connfd : maxfd;
		}

		for (int i = sockfd+1; i < maxfd+1; i++)
		{
			if (FD_ISSET(i, &tmpfds))
			{
				memset(buff, 0, sizeof(buff));
				ssize_t size = recv(i, buff, sizeof(buff), 0);
				if (size < 0)
				{
					FD_CLR(i, &fds);
					close(i);
					perror("fail recv");
					continue;
				}
				else if (0 == size)
				{
					FD_CLR(i, &fds);
					close(i);
					printf("cli offline\n");
					continue;					
				}
				printf("cli--->ser: %s\n", buff);
				strcat(buff, "----->[ok]");
				size = send(i, buff, strlen(buff), 0);
				if (size < 0)
				{
					FD_CLR(i, &fds);
					close(i);
					perror("fail send");
					continue;				
				}
			}

		}

	}
	return 0;
}

1.函数接口
    (1)select 
       int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
       功能:
            监听文件描述符集合
       参数:
            nfds:最大文件描述符个数+1
            readfds:读文件描述符集合
            writefds:写文件描述符集合
            exceptfds:其余文件描述符集合
            timeout:设定超时时间
            NULL:永远等待,直到有数据发生
       返回值:
            成功返回产生事件的文件描述符个数
            失败返回-1     
2. void FD_CLR(int fd, fd_set *set);
    功能:将fd从文件描述符集合中移除        
    
3. int  FD_ISSET(int fd, fd_set *set);
    功能:判断fd是否仍在文件描述符集合中        
    
4. void FD_SET(int fd, fd_set *set);
    功能:将fd加入文件描述符集合            
    
5. void FD_ZERO(fd_set *set);
    功能:将文件描述符集合清0 

6.select函数缺点

(1)select监听文件描述符个数上限为1024
(2)select监听的文件描述符集合在应用层,事件发时,内核数据需要传递给应用层,造成资源开销
(3)select需要手动检测产生事件的文件描述符
(4)select只能工作在水平触发模式(低速模式)
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值