服务器使用 select 模型实现接受多个客户端连接,以及转发消息
客户端要求:使用 poll 模型解决 技能够 read 读取服务器发来的消息,又能够scanf读取键盘输入的信息 客户端服务器不开启额外线程和进程
服务器代码:
#include <my_head.h>
#define MAX_CLIENTS 10
#define BUFFER_SIZE 128
void insert_client(int * client_arr,int *client_arr_len,int new_client)
{
if((*client_arr_len) >= MAX_CLIENTS)
{
printf("client list full\n");
return ;
}
client_arr[*client_arr_len] = new_client;
(*client_arr_len) ++;
return ;
}
void remove_client(int * client_arr,int * client_arr_len,int tar_client)
{
int i,j,len = * client_arr_len;
for(i=0;i<len;i++)
{
if(tar_client == client_arr[i])
{
for(j=i;j<len-1;j++)
{
client_arr[j] = client_arr[j+1];
}
client_arr[j] = -1;
(*client_arr_len) --;
break ;
}
}
return ;
}
int main(int argc, const char *argv[])
{
if(argc<2)
{
printf("请输入端口号\n");
return -1;
}
//将外部传入字符串转化成整数
short port = atoi(argv[1]);
//创建服务器端套接字
int sever = socket(AF_INET,SOCK_STREAM,0);
if(-1==sever)
{
ERRORLOG("socket failed");
return -1;
}
struct sockaddr_in addr = {0};
addr.sin_family=AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("0.0.0.0"); // 绑定到所有接口
if(-1==bind(sever,(struct sockaddr *)&addr,sizeof(addr)))
{
perror("bind error");
close(sever);
return -2;
}
listen(sever,10); //监控服务器
printf("sever started on port\n");
int client_arr[MAX_CLIENTS] = {0};
int client_arr_len = 0;
//创建接收客户消息监视列表和激活列表
fd_set readfds,backup_readfds;
//监视列表清零
FD_ZERO(&readfds);
FD_SET(sever,&readfds);
int max_fd = sever;
while(1)
{
int activity = select(max_fd + 1, &backup_readfds, NULL, NULL, NULL);
if (activity < 0)
{
perror("select error");
continue;
}
// 检查是否有新客户端连接
if (FD_ISSET(sever, &backup_readfds))
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client = accept(sever, (struct sockaddr *)&client_addr, &client_len);
if (client == -1)
{
perror("accept failed");
continue;
}
printf("新客户端ip=%s\n",inet_ntoa(client_addr.sin_addr));
printf("新客户端port=%d\n",ntohs(client_addr.sin_port));
//将新客户端存入客户端数组,用于后续遍历数组查找目标客户端
insert_client(client_arr,&client_arr_len,client);
//将客户端加入监视列表
FD_SET(client,&readfds);
if (client > max_fd) max_fd = client;
}
//遍历客户端数组,找出当前连接的客户端
for(int i=0;i<client_arr_len;i++)
{
int client = client_arr[i];
if(FD_ISSET(client,&backup_readfds))
{
char buf[BUFFER_SIZE] = {0};
ssize_t res = read(client,buf,sizeof(buf));
if(res<=0)
{
close(client);
printf("客户端断开连接\n");
//从监视列表中删除断开客户端
FD_CLR(client,&readfds);
//从客户端数组中删除断开客户端
remove_client(client_arr,&client_arr_len,client);
}
else
{
printf("客户端发来消息:%s\n",buf);
for(int j=0;j<client_arr_len;j++)
{
int dest_fd = client_arr[j];
if(client != dest_fd)
{
write(client,buf,res);
}
}
}
}
}
}
close(sever);
return 0;
}
客户端代码:
#include <my_head.h>
#define MAX_CLIENT 10
#define BUFFER_SIZE 128
void insert_fd(struct pollfd* list,int* list_len,struct pollfd new_fd)
{
if((*list_len) >= MAX_CLIENT)
{
printf("poll list full");
}
list[*list_len] = new_fd;
(*list_len) ++;
return ;
}
void remove_fd(struct pollfd *list,int *list_len,int tar_fd)
{
int i,j,len = *list_len;
for(i=0;i<len;i++)
{
if(list[i].fd == tar_fd)
{
for(j=0;j<len-1;j++)
{
list[j] = list[j+1];
}
(*list_len)--;
break;
}
}
return ;
}
int main(int argc, const char *argv[])
{
if(argc<2)
{
printf("请输入端口号\n");
return -1;
}
//将外部传入字符串转化成整数
short port = atoi(argv[1]);
int client = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr = {0};
addr.sin_family=AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("192.168.127.97");
connect(client,(struct sockaddr*)&addr,sizeof(addr));
listen(client,10);
struct pollfd list[MAX_CLIENT] = {0};
int list_len = 0;
struct pollfd poll_client ={.fd =client ,.events = POLL_OUT, .revents = 0 };
insert_fd(list,&list_len,poll_client);
char buf[BUFFER_SIZE];
while(1)
{
memset(buf,0,BUFFER_SIZE);
poll(list,list_len,-1);
for(int i=0;i<list_len;i++)
{
if(list[i].revents == 0)
{ continue ;}
else if(list[i].revents == POLL_OUT)
{
printf("请输入消息:\n");
scanf("%s",buf);
getchar();
//写入数据
write(client,buf,BUFFER_SIZE);
}
else if(list[i].revents == POLL_IN)
{
//读取数据
read(client,buf,BUFFER_SIZE);
printf("接收消息: %s\n",buf);
}
}
}
close(client);
return 0;
}
1496

被折叠的 条评论
为什么被折叠?



