版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27312943/article/details/79108718
1 推荐博客
https://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html
我自己select()函数的使用和使用多路复用改写服务端代码理解的还不是特别深入,推荐上面的博客。
2 使用select()函数改写服务端源代码
服务端:
/*net_selecy.c*/
//多路复用
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#define PORT 4321
#define MAX_QUE_CONN_NM 5
#define BUFFER_SIZE 1024
#define MAX_SOCK_FD FD_SETSIZE
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
fd_set inset,tmp_inset;
int sockid; //套接字描述符
int client_fd; //接收到的套接字ID
int i=0;
int sin_size;
char buf[BUFFER_SIZE];
int fd;
int recvbytes;
sockid=socket(AF_INET,SOCK_STREAM,0);
if(sockid == -1)
{
//创建套接字失败
printf("socket error\n");
exit(1);
}
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(PORT); //端口号
server_sockaddr.sin_addr.s_addr=INADDR_ANY; //IP地址 //IP地址可以指定,或者使用宏INADDR_ANY
//表示运行套接字与服务器的任一网络接口进行绑定
bzero(&(server_sockaddr.sin_zero),8);
setsockopt(sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
if( bind(sockid,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1 )
{
printf("bind error\n");
exit(1);
}
printf("bind success\n");
if( listen(sockid,MAX_QUE_CONN_NM) == -1 )
{
printf("listen error\n");
exit(1);
}
printf("listen...\n");
/*将指定的文件描述符集清空,在对文件描述符集合进行设置前,
必须对其进行初始化,如果不清空,由于在系统分配内存空间后,
通常并不作清空处理,所以结果是不可知的。*/
FD_ZERO(&inset);
/**************
将fd加入set集合
**************/
FD_SET(sockid,&inset);
while(1)
{
/*文件描述符集合的备份,这样可以避免每次都进行初始化*/
tmp_inset=inset;
sin_size=sizeof(struct sockaddr_in);
memset(buf,0,sizeof(buf));
/*调用select()函数*/
/*******************************
函数原型:int select(int maxfd,
fd_set *rdset,
fd_set *wrset,
fd_set *exset,
struct timeval *timeout);
函数参数:maxfd 需要监视的最大的文件描述符值+1
rdset 需要检测的可读文件描述符的集合
wrset 可写文件描述符的集合
exset 异常文件描述符的集合
timeout 构用于描述一段时间长度,
如果在这个时间内,
需要监视的描述符没有事件发生则函数返回,返回值为0
*******************************/
if( !(select(MAX_SOCK_FD,&tmp_inset,NULL,NULL,NULL) > 0) )
{
printf("select error\n");
}
for(fd=0;fd<MAX_SOCK_FD;fd++)
{
/*FD_ISSET()用于测试指定的文件描述符是否在该集合中*/
if(FD_ISSET(fd,&tmp_inset) > 0)
{
if(fd == sockid)
{
/*服务端接受客户端的请求*/
if( (client_fd=accept(sockid,(struct sockaddr*)&client_sockaddr,&sin_size)) == -1 )
{
printf("accept error\n");
exit(1);
}
/*将新连接的客户端套接字加入到观察列表中*/
FD_SET(client_fd,&inset);
printf("new connection from %d(socket)\n",client_fd);
}
else
{
/*处理从客户端发来的消息*/
if( (recvbytes= recv(client_fd,buf,BUFFER_SIZE,0) ) >0 )
{
printf("receive data %d\n",strlen(buf));
printf("receive a message:%s\n",buf);
}
else
{
close(fd);
FD_CLR(fd,&inset);
printf("client %d(socket) has left\n",fd);
}
}
}/*end if(FD_ISSET(fd,&tmp_inset) > 0)*/
} //end for
} /*end while(1)*/
close(sockid);
exit(0);
}
客户端:
/*client.c*/
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 4321
#define BUFFER_SIZE 1024
int main(int argc,char *argv[])
{
struct hostent *host;
int sockid; //套接字描述符
int sendbyts; //实际发送的字节数
char buf[BUFFER_SIZE];
struct sockaddr_in serv_addr;
if(argc<3)
{
fprintf(stderr,"USAGE:./client Hostname(or ip address) Text\n");
exit(1);
}
/*地址解析函数*/
/***************************
函数原型:struct hostent *gethostbyname(const char *hostname);
函数参数:hostname 主机名
函数返回值:成功 指向hostent的指针
失败 -1
*****************************/
if( (host=gethostbyname(argv[1])) == NULL )
{
printf("gethostbyname error\n");
exit(1);
}
memset(buf,0,sizeof(buf));
sprintf(buf,"%s",argv[2]);
//创建socket
sockid=socket(AF_INET,SOCK_STREAM,0);
if(sockid == -1)
{
//创建套接字失败
printf("socket error\n");
exit(1);
}
/*设置socket_in中的相关参数*/
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(PORT); //端口号
serv_addr.sin_addr=*((struct in_addr *)host->h_addr); //IP地址 //IP地址可以指定,或者使用宏INADDR_ANY
//表示运行套接字与服务器的任一网络接口进行绑定
bzero(&(serv_addr.sin_zero),8);
//连接服务器
/*调用connect()函数主动发起对服务器端的连接*/
/************************
函数原型: int connect(int sockfd, const struct sockaddr * addr, socklen_t *addrlen)
函数参数: sockfd 套接字描述符
addr 客户端地址
addrlen 地址长度
函数返回值: 成功 接收到的非负套接字
失败 -1
***********************/
if( connect(sockid,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)) == -1 )
{
printf("connect error\n");
exit(1);
}
/*发送消息给服务端*/
/*****************
函数原型:int send(int sockfd,const void *msg,int len,int flags)
函数参数:sockfd 套接字描述符
msg 指向要发送数据的指针
len 数据长度
flags 一般为0
函数返回值:成功 实际发送的字节数
失败 -1
******************/
if( (sendbyts=send(sockid,buf,sizeof(buf),0)) == -1 )
{
printf("send error\n");
exit(1);
}
sleep(5);
close(sockid);
return 0;
}
运行结果
服务端
客户端1
客户端2