#include <myhead.h>
#define SER_IP "192.168.122.128"
#define SER_PORT 1515
#define MAX(a,b) ((a)>(b)?(a):(b))
int main(int argc, const char *argv[])
{
//定义一个信息传递容器msg
struct MSG
{
char type[20];
char name[20];
char data[128];
}msg;
//创建套接字
int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd==-1)
{
perror("socket error");
return -1;
}
//将端口号快速重用
int reuse=-1;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
//填充服务器地址端口信息
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(SER_IP);
//将套接字与服务器地址信息绑定
if(bind(listenfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("bind error");
return -1;
}
//将服务器开启被动监听模式
listen(listenfd,128);
//基于TCP的服务器搭建完成
printf("服务端开启成功,IP地址为%s,端口号为%d\n",SER_IP,SER_PORT);
//采用IO多路复用select函数实现并发服务器
fd_set read_fs,read_temp_fs;
FD_ZERO(&read_fs);
FD_SET(listenfd,&read_fs);
FD_SET(0,&read_fs);
int max=listenfd;
//定义客户端数组存储所有已连接客户端信息
struct sockaddr_in cli[128];
struct sockaddr_in cin;
socklen_t socklen_cin=sizeof(cin);
int clifd=-1;
while(1)
{
read_temp_fs=read_fs;
select(max+1,&read_temp_fs,NULL,NULL,NULL);
for(int i=0;i<=max;i++)
{
if(!FD_ISSET(i,&read_temp_fs))
{
continue;
}
//处理accept事件
else if(i==listenfd)
{
if((clifd=accept(listenfd,(struct sockaddr*)&cin,&socklen_cin))==-1)
{
perror("accept error");
return -1;
}
printf("[%s:%d]:发来链接请求\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
max=MAX(clifd,max);
FD_SET(clifd,&read_fs);
//将cin的地址信息存储在已链接的客户端数组中
cli[clifd]=cin;
}
//给所有已连接的客户端发送消息
else if(i==0)
{
char sbuf[128]="";
scanf("%s",sbuf);
for(int j=4;j<=max;j++)
{
sendto(j,sbuf,sizeof(sbuf),0,(struct sockaddr*)&cli[j],sizeof(cli[j]));
}
}
//接收客户端发来的消息
else
{
int res=recv(i,&msg,sizeof(msg),0);
//判断客户端是否断开连接
if(res==0)
{
printf("[%s,%d]:已下线\n",inet_ntoa(cli[i].sin_addr),ntohs(cli[i].sin_port));
FD_CLR(i,&read_fs);
close(i);
if(max==i)
{
max--;
}
continue;
}
//判断msg.type的类型
//all类型向所有已连接的用户发送信息
else if(strcmp(msg.type,"all")==0)
{
for(int j=4;j<=max;j++)
{
sendto(j,&msg,sizeof(msg),0,(struct sockaddr*)&cli[j],sizeof(cli[j]));
}
}
printf("%s:%s\n",msg.name,msg.data);
}
}
}
close(listenfd);
return 0;
}
#include <myhead.h>
#define SER_IP "192.168.122.128"
#define SER_PORT 1515
#define USR_IP "192.168.122.128"
#define USR_PORT 8888
int main(int argc, const char *argv[])
{
struct MSG
{
char type[20];
char name[20];
char data[128];
}msg;
//创建通信套接字
int cfd=-1;
if((cfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket error");
return -1;
}
//端口号快速重用
int reuse=-1;
if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
//填充客户端地址信息
struct sockaddr_in cin;
cin.sin_family=AF_INET;
cin.sin_port=htons(USR_PORT);
cin.sin_addr.s_addr=inet_addr(USR_IP);
socklen_t socklen_cin=sizeof(cin);
//绑定
if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin))==-1)
{
perror("bind error");
return -1;
}
//填充服务器端地址信息
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(SER_PORT);
sin.sin_addr.s_addr=inet_addr(SER_IP);
socklen_t socklen_sin=sizeof(sin);
//登录客户端
printf("请输入客户名:");
scanf("%s",msg.name);
strcpy(msg.type,"link");
strcpy(msg.data,"已连接服务器");
//连接服务器端
if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("connect error");
return -1;
}
printf("连接成功\n");
send(cfd,&msg,sizeof(msg),0);
//采用IO多路复用select函数
fd_set read_fs,read_temp_fs;
FD_ZERO(&read_fs);
FD_SET(cfd,&read_fs);
FD_SET(0,&read_fs);
int max=cfd;
while(1)
{
read_temp_fs=read_fs;
select(max+1,&read_temp_fs,NULL,NULL,NULL);
for(int i=0;i<=max;i++)
{
if(!FD_ISSET(i,&read_temp_fs))
{
continue;
}
//给服务器端发送消息
else if(i==0)
{
scanf("%s",msg.type);
if(strcmp(msg.type,"all")==0)
{
printf("您已进入聊天室,现在发送的消息聊天室内所有人可见\n");
scanf("%s",msg.data);
if(strcmp(msg.data,"quit")==0)
{
strcpy(msg.type,"quit");
printf("您已退出聊天室\n");
break;
}
send(cfd,&msg,sizeof(msg),0);
}
else
{
printf("输入格式错误,请输入“all”进入聊天室\n");
}
}
else
{
//接收来自服务器端的消息
recv(i,&msg,sizeof(msg),0);
printf("%s:%s\n",msg.name,msg.data);
}
}
}
close(cfd);
return 0;
}