linux c IO多路复用之select函数模型,构建C/S来实现服务器与客户端之间进行通信
程序员文章站
2022-06-06 09:20:32
...
//"util.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/time.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/select.h>
#define backlogs 10
#define BUF_SIZE 50
int Socket(int domain,int type,int protocol)
{
int fd=socket(domain,type,protocol);
if(fd==-1)
return -1;
return fd;
}
int Bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
{
int ret=bind(sockfd,addr,addrlen);
if(ret==-1)
return -1;
return ret;
}
int Listen(int sockfd,int backlog)
{
int ret=listen(sockfd,backlog);
if(ret==-1)
return -1;
return ret;
}
int start_up(const char* ip,int port)
{
int fd=Socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in ser_addr;
ser_addr.sin_family=AF_INET;
ser_addr.sin_port=htons(port);
ser_addr.sin_addr.s_addr=inet_addr(ip);
int on=1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(int));
socklen_t addrlen=sizeof(struct sockaddr);
Bind(fd,(struct sockaddr*)&ser_addr,addrlen);
Listen(fd,backlogs);
return fd;
}
//ser.c 服务器端
#include"util.h"
int main(int argc,char *argv[])
{
int i,j,n,maxi;
int nready,client[FD_SETSIZE];//FD_SETSIZE 1024
int maxfd,listenfd,connfd,sockfd;
char buf[BUF_SIZE];
char str[INET_ADDRSTRLEN];//16
struct sockaddr_in clie_addr,serv_addr;
socklen_t clie_addr_len;
fd_set rset,allset;
listenfd=start_up(argv[1],atoi(argv[2]));
maxfd=listenfd; //起初listenfd 即为最大文件描述符
maxi=-1; //将来用作client[]的下标,初始值指向下标为-1的位置
for(i=0;i<FD_SETSIZE;i++)//1024
client[i]=-1;//用-1初始化client
FD_ZERO(&allset);
FD_SET(listenfd,&allset); //构造select监控文件描述符集
while(1)
{
rset=allset; //每次循环时都从新设置select监控信号集
nready=select(maxfd+1,&rset,NULL,NULL,NULL);//rset在select返回后在改变 //没有发生可读事件的fd将被置0
if(nready<0)
{
perror("select error\n");
continue;
}
if(FD_ISSET(listenfd,&rset)) //说明有新的客户端连接
{
clie_addr_len=sizeof(struct sockaddr);
connfd=accept(listenfd,(struct sockaddr *)&clie_addr,&clie_addr_len);//accept() 不会阻塞
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET,&clie_addr.sin_addr,str,sizeof(str)),
ntohs(clie_addr.sin_port));
for(i=0;i<FD_SETSIZE;i++)
{
if(client[i]==-1)
{
client[i]=connfd; //保存accept返回的文件描述符到client[]里
break;
}
}
if(i==FD_SETSIZE) //达到select能监控的文件个数上限1024
{
fputs("too many clients!!! ,The Ser is Load",stderr);
exit(1);
}
FD_SET(connfd,&allset);
if(connfd>maxfd)
maxfd=connfd;
if(i>maxi)
maxi=i;
if(--nready==0)
continue;
}
for(i=0;i<=maxi;i++)
{
if( (sockfd=client[i])<0)
continue;
if(FD_ISSET(sockfd,&rset))
{
if( (n=recv(sockfd,buf,sizeof(buf),0))==0 )
{
close(sockfd);
FD_CLR(sockfd,&rset);
client[i]=-1;
}
else if(n>0)
{
for(j=0;j<n;j++)
buf[j]=toupper(buf[j]);
send(sockfd,buf,n,0);
}
if(--nready==0)
break;
}
}
}
close(listenfd);
return 0;
}
//客户端
//cli.c
#include"util.h"
int main(int argc,char *argv[])
{
char sendbuf[128];
char recvbuf[128];
socklen_t addrlen=sizeof(struct sockaddr);
int cli_fd=socket(AF_INET,SOCK_STREAM,0);
if(cli_fd==-1)
return -1;
struct sockaddr_in seraddr;
seraddr.sin_family=AF_INET;
seraddr.sin_port=htons(atoi(argv[2]));
seraddr.sin_addr.s_addr=inet_addr(argv[1]);
int ret=connect(cli_fd,(struct sockaddr*)&seraddr,addrlen);
if(ret==-1)
{
perror("connect error!\n");
return -1;
}
else
printf("success\n");
while(1)
{
printf("Cli:>");
scanf("%s",sendbuf);
send(cli_fd,sendbuf,strlen(sendbuf)+1,0);
recv(cli_fd,recvbuf,128,0);
printf("From Self Cli:%s\n",recvbuf);
}
close(cli_fd);
return 0;
}