TCPC/S模型中使用seclect函数

//使用select相比于前面多线程或者多进程而言能更好利用资源,其中最大的一个优点就是在accept函数中原来我们是阻塞等待客户端的连接,而使用select之后我们把套接字放在一个集合中对其进行检查,有客户端连接就直接调用accept函数就好了
//这里就直接把服务端的代码放下面了

/*************************************************************************
	> File Name: server.c
	> Author: chencj
	> Mail: 1378755306@qq.com 
	> Created Time: 2020年08月04日 星期二 10时41分36秒
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/select.h>

const int N = 128;
int cnt = 0;
int max_scokfd;  //最大的文件描述符   创建套接字的时候文件描述符是每次递增1的
void sys_err(char *msg)
{
	perror(msg);
	exit(1);
}

int main(int argc, char const *argv[])
{
	if(argc < 3) {
		sys_err("less input\n");
	}
	int lfd,cfd; //监听套接字   通信套接字
	char buf[N];
	struct sockaddr_in serve_addr,cli_addr;
	lfd = socket(AF_INET,SOCK_STREAM,0);
	if(lfd == -1) sys_err("socket error\n");

	int vel;
	if(setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,(void*)&vel,sizeof(int)) == -1)  //设置端口复用
	sys_err("setsockopt error\n");
	//sockaddr
	serve_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serve_addr.sin_family = AF_INET;
	serve_addr.sin_port = htons(atoi(argv[2]));
	socklen_t clen = sizeof(cli_addr);
	//bind
	if(bind(lfd,(struct sockaddr*)&serve_addr,sizeof(serve_addr)) == -1) sys_err("bind error\n");
	//listen
	if(listen(lfd,N) == -1) sys_err("listen error\n");
	//fd_set
	fd_set lset,all_set;  //一个用来监听   一个备份使用
	FD_ZERO(&lset);FD_ZERO(&all_set);
	FD_SET(lfd,&all_set);  //把监听套接字放到集合中去
	max_scokfd = lfd;
	while(1)
	{
		lset = all_set;
		int res;
		res = select(max_scokfd+1,&lset,NULL,NULL,0);   //res的返回值是看集合中有多少要与服务器进行交互的套接字的数量
		if(res < 0) sys_err("select error\n");

		for(int i=lfd;i<=max_scokfd;i++)
		{
			if(FD_ISSET(i,&lset))  //套接字在这个集合中返回1
			{
				//listen
				if(i == lfd)  //如果这个套接字等于监听套接字就说明有新的客户端要与服务端进行通信
				{
					cfd = accept(i,(struct sockaddr*)&cli_addr,&clen);  //原来是=多线程或者多进程中是阻塞等待,现在不用阻塞
					FD_SET(cfd,&all_set);  //把这个套接字加入到集合中去
					if(cfd > max_scokfd) max_scokfd = cfd;
					cnt++; //表示当前有多少客户端与服务器连接
					printf("[ip : %s---port : %d]---%d Connect\n",inet_ntoa(cli_addr.sin_addr),
						ntohs(cli_addr.sin_port),cnt);
				}
				else
				{
					//进行通信
					memset(buf,'\0',sizeof(buf));
					int ret;
					ret = read(i,buf,sizeof(buf));
					if(ret == 0) {
						FD_CLR(i,&all_set);  //把这个套接字从集合中清除
						close(i);
						if(max_scokfd == i) max_scokfd--;
						cnt--;
					}
					else
					{
						printf("[ip : %s---port : %d]---Data:%s\n",inet_ntoa(cli_addr.sin_addr),
							ntohs(cli_addr.sin_port),buf);
						write(i,"Accept",7);
					}
				}
				
			}
		}
	}
	close(lfd);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

译制片~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值