运行1个服务器和2个客户端
实现效果:
服务器和2个客户端互相聊天,服务器和客户端都需要使用select模型去实现
服务器要监视2个客户端是否连接,2个客户端是否发来消息以及服务器自己的标准输入流
客户端要监视服务器是否发来消息以及客户端自己的标准输入流
在不开线程的情况下,实现互相聊天
服务器代码
#include<myhead.h>
//添加客户端数组元素
void insert_client(int* client_arr,int* len,int client)
{
client_arr[*len]=client;
(*len)++;
}
//查找客户端数组元素位置
int find_client(int* client_arr,int len,int client)
{
for(int i=0;i<len;i++)
{
if(client_arr[i]==client)
{
return i;
}
return -1;
}
}
//删除客户端数组元素
void remove_client(int* client_arr,int* len,int client)
{
int tar=find_client(client_arr,*len,client);
if(tar==-1){return;}
int i=-1;
for(i=tar;i<*len-1;i++)
{
client_arr[i]=client_arr[i+1];
}
client_arr[i]=0;
(*len)--;
}
int main(int argc, char const *argv[])
{
if(argc!=2)
{
printf("请输入正确的端口号\n");
return 1;
}
int port=atoi(argv[1]);
fd_set readfds;//描述符集合
FD_ZERO(&readfds);
int client_arr[100]={0};//客户端数组
int client_count=0;//个数
//绑定端口地址
int server=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
//客户端
struct sockaddr_in cin;
socklen_t cin_len=sizeof(cin);
//绑定
if(bind(server,(struct sockaddr*)&addr,sizeof(addr))==-1)
{
perror("bind");
return -1;
}
listen(server,100);//监听
FD_SET(server,&readfds);//服务器添加到集合
FD_SET(STDIN_FILENO,&readfds);//服务器标准输入添加
while(1)
{
fd_set temp=readfds;
select(FD_SETSIZE,&temp,0,0,0);//监视
//判断服务器是否激活
if(FD_ISSET(server,&temp))
{
int client=accept(server,(struct sockaddr*)&cin,&cin_len);
printf("[%s:%d]客户端连接成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
FD_SET(client,&readfds);//放入集合
insert_client(client_arr,&client_count,client);//添加数组中
}
//判断标准输入是否激活
else if(FD_ISSET(STDIN_FILENO,&temp))
{
char buf[128]="system:";
int res=read(STDIN_FILENO,buf+7,128);//读取标准输入
//遍历数组发送
for(int i=0;i<client_count;i++)
{
send(client_arr[i],buf,strlen(buf),0);
}
}
//判断每个客户端是否激活
else
{
for(int i=0;i<client_count;i++)
{
int client=client_arr[i];
if(FD_ISSET(client,&temp))
{
char buf[128]={0};
int res=read(client,buf,128);
if(res==0)
{
printf("[%s:%d]客户端断开连接\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
FD_CLR(client,&readfds);//清空
remove_client(client_arr,&client_count,client);//删除
close(client);
break;
}
char buf1[128]={0};
sprintf(buf1,"[%s:%d]%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
printf("%s",buf1);
//遍历数组
for(int i=0;i<client_count;i++)
{
if(client!=client_arr[i])//不发给自己
{
send(client_arr[i],buf1,strlen(buf1),0);
}
}
}
}
}
}
return 0;
}
客户端代码
#include<myhead.h>
int main(int argc, char const *argv[])
{
if(argc!=2)
{
printf("请输入正确的端口号\n");
return 1;
}
fd_set readfds;
FD_ZERO(&readfds);
int cfd=socket(AF_INET,SOCK_STREAM,0);
if(cfd==-1)
{
perror("socket error");
return -1;
}
printf("cfd=%d\n",cfd);
struct sockaddr_in cin;
cin.sin_family=AF_INET;
cin.sin_port=htons(atoi(argv[1]));
cin.sin_addr.s_addr=inet_addr("127.0.0.1");
if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin))==-1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(6666);
sin.sin_addr.s_addr=inet_addr("127.0.0.1");
//放置客户端和标准输入
FD_SET(cfd,&readfds);
FD_SET(STDIN_FILENO,&readfds);
//连接服务器
if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("connect error");
return -1;
}
printf("连接服务器成功\n");
while(1)
{
fd_set temp=readfds;
select(FD_SETSIZE,&temp,0,0,0);//监视客户端和标准输入
if(FD_ISSET(cfd,&temp))
{
char buf[128]="";
recv(cfd,buf,sizeof(buf),0);
printf("%s",buf);
}
else
{
char buf[128]="";
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
if(strcmp(buf,"quit")==0)
{
break;
}
send(cfd,buf,strlen(buf),0);
}
}
close(cfd);
return 0;
}