玩一下linux下的IO多路复用之select-----实现多客户端访问服务器
程序员文章站
2022-06-06 09:25:09
...
趁着还没想睡觉,写一下io多路复用的select实现,支持多个客户端访问服务器,以下程序还有点瑕疵,等有时间再改,不说了,太困了,先睡觉。
服务器实现:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define MAXMSG 1024
//处理信息接口
void handleMsg(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset,const char* str)
{
char buf[MAXMSG];
char printBuf[MAXMSG];
int i;
for (i = 0; i< maxFds; i++)
{
if (clientSockFds[i] != -1) //如果条件成立,则有连接的客户端
{
if (FD_ISSET(clientSockFds[i], pRset)) //判断是哪一个客户端的事件
{
int nread = read(clientSockFds[i], buf, MAXMSG); //读取客户端socket流
if (nread < 0) //对方异常。
{
perror("read error");
close(clientSockFds[i]);
FD_CLR(clientSockFds[i], pAllset);
clientSockFds[i] = -1;
continue;
}
else if (nread == 0) //对方挂断,返回0
{
printf("%s",str);
printf(" client close the connection\n");
close(clientSockFds[i]);
//如果对方挂断。则从文件集中清除监听该文件描述符
FD_CLR(clientSockFds[i], pAllset);
clientSockFds[i] = -1;
continue;
}
else if (nread > 0)
{
sprintf(printBuf,"%s: %s",str,buf);
printf("recv %s\n", printBuf);
}
//write(clientSockFds[i], buf, nread);
}
}
}
}
int main(int argc, char **argv)
{
int servPort = 6666;
char buf[MAXMSG];
int clientSockFds[FD_SETSIZE];
printf("FD_SETSIZE=%d\n",FD_SETSIZE);
//1、创建套接字
int socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd < 0)
{
perror("socket error");
return -1;
}
//作用就是程序异常退出,再重新运行不会绑定端口失败
int opt = 1;
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("setsockopt error");
}
//2、配置网络
struct sockaddr_in clientaddr, serveraddr;
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(servPort);
int socklen=sizeof(struct sockaddr_in);
//3、绑定
if(bind(socketfd,(struct sockaddr*)&serveraddr,socklen) == -1)
{
perror("bind error");
exit(-1);
}
//4、监听
if (listen(socketfd, 1024) < 0)
{
perror("listen error");
return -1;
}
int i = 0;
for (i = 0; i< FD_SETSIZE; i++)
{
clientSockFds[i] = -1; //给客户端文件描述符赋值
}
fd_set allset, rset; //声明文件描述符
FD_ZERO(&allset); //把集合设置为空集
//5、将监听的socketfd 放到select集合中监听
FD_SET(socketfd, &allset);
int maxfd = socketfd;
printf("server port is %d\n", servPort);
printf("max connection: %d\n", FD_SETSIZE);
while (1)
{
//因为select 每收到一次监听事件,便会从rset把相应的文件描述符从监听集合中清除
rset = allset; //定义两个文件集合,一个用来备份
//6、select阻塞
int nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0)
{
perror("select error");
continue;
}
//7、如果服务端的套接字有活动
if (FD_ISSET(socketfd, &rset))
{
//8、接收连接
int connfd = accept(socketfd, (struct sockaddr*) &clientaddr, &socklen);
if (connfd < 0)
{
perror("accept error");
continue;
}
sprintf(buf, "connect from %s:%d", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
printf("%s\n",buf);
for (i = 0; i< FD_SETSIZE; i++)
{
if (clientSockFds[i] == -1) //
{
clientSockFds[i] = connfd; //将客户端连接的文件描述符放到clientSockFds数组
break;
}
}
if (i == FD_SETSIZE)
{
fprintf(stderr, "too many connection, more than %d\n", FD_SETSIZE);
close(connfd);
continue;
}
if (connfd > maxfd)
{
maxfd = connfd;
}
//添加或者删除都留着allset
FD_SET(connfd, &allset);
//超时继续
if (--nready <= 0)
continue;
}
//9、处理客户端发送的信息
handleMsg(clientSockFds, maxfd, &rset, &allset,buf);
}
}
客户端实现:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define MAXMSG 1024
int main()
{
int connfd=socket(AF_INET,SOCK_STREAM,0);
if(connfd==-1)
{
printf("creat socket failed\n");
}
//取消端口绑定限制
int opt = 1;
if (setsockopt(connfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))<0)
{
printf("setsockopt failed\n");
return -1;
}
struct sockaddr_in addrSrc;
bzero(&addrSrc,sizeof(addrSrc));
addrSrc.sin_family=AF_INET;
addrSrc.sin_port=htons(6666);
addrSrc.sin_addr.s_addr=inet_addr("127.0.0.1");
if (connect(connfd, (struct sockaddr *) &addrSrc, sizeof(addrSrc)) < 0)
{
printf("connect error\n");
return -1;
}
printf("This is client\n");
while(1)
{
//发送信息
char sendBuf[100]={0};
scanf("%s",sendBuf);
send(connfd,sendBuf,strlen(sendBuf)+1,0);
}
close(connfd);
printf("exit\n");
return 0;
}