client
#include
//定义信息结构体
struct Msg
{
char type;
char name[20];
char text[128];
};
int main(int argc, const char *argv[])
{
//终端输入服务端ip地址及端口号
if(argc!=3)
{
printf("输入错误!!!!\n");
printf("请输入ip地址及端口号\n");
return -1;
}
//创建套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd==-1)
{
perror("socket error");
return -1;
}
//填充服务端信息地址结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=inet_addr(argv[1]);
sin.sin_port=htons(atoi(argv[2]));
socklen_t socklen=sizeof(sin);
//定义收发消息结构体
struct Msg send_msg;
struct Msg recv_msg;
//先登录
printf("请输入姓名>>");
send_msg.type='L';
char name[20]="";
fgets(name,sizeof(name),stdin);
name[strlen(name)-1]=0;
strcpy(send_msg.name,name);
//给服务端发上线消息
sendto(cfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&sin,sizeof(sin));
//定义检测文件描述符集合
fd_set readfds,tempfds;
FD_ZERO(&readfds);
FD_SET(cfd,&readfds);
FD_SET(0,&readfds);
//接收select返回值
int res=0;
while(1)
{
tempfds=readfds;
//检测集合中是否有事件发生
res=select(cfd+1,&tempfds,NULL,NULL,NULL);
if(res==-1)
{
perror("select error");
return -1;
}else if(res==0)
{
printf("time out\n");
return -1;
}
//触发终端输入
if(FD_ISSET(0,&tempfds))
{
//把输入内容存储到发送消息结构体中
bzero(send_msg.text,sizeof(send_msg.text));
fgets(send_msg.text,sizeof(send_msg.text),stdin);
send_msg.text[strlen(send_msg.text)-1]=0;
//quit退出客户端
if(strcmp(send_msg.text,"quit")==0)
{
send_msg.type='Q';
sendto(cfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&sin,sizeof(sin));
close(cfd);
break;
}else
{
send_msg.type='C';
sendto(cfd,&send_msg,sizeof(send_msg),0,(struct sockaddr*)&sin,sizeof(sin));
}
}
//触发接收消息
if(FD_ISSET(cfd,&tempfds))
{
bzero(recv_msg.text,sizeof(recv_msg.text));
res=recvfrom(cfd,&recv_msg,sizeof(recv_msg),0,NULL,NULL);
if(res<0)
{
perror("recvfrom error");
return -1;
}
if(recv_msg.type=='L')
{
printf("---%s已上线---\n",recv_msg.name);
}
if(recv_msg.type=='Q')
{
printf("---%s已下线---\n",recv_msg.name);
}
if(recv_msg.type=='C')
{
printf("%s:%s\n",recv_msg.name,recv_msg.text);
}
}
}
close(cfd);
return 0;
}
serve
#include
//信息结构体
struct Msg
{
char type;
char name[20];
char text[128];
};
int main(int argc, const char *argv[])
{
//判断从终端输入字符串的个数
if(argc!=3)
{
printf("输入错误!!!\n");
printf("请输入ip地址及端口号\n");
return -1;
}
int sfd=-1;
if((sfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
{
perror("socket error");
return -1;
}
int reuse=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
//用终端输入ip及端口号填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[2]));
sin.sin_addr.s_addr=inet_addr(argv[1]);
//绑定服务器地址信息
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("bind error");
return -1;
}
//创建客户端地址信息结构体用于接收客户端信息
struct sockaddr_in cin;
socklen_t socklen=sizeof(cin);
struct sockaddr_in arr_cin[1024];
//定义检测文件描述符集合
fd_set readfds,tempfds;
FD_ZERO(&readfds);
FD_SET(0,&readfds);
FD_SET(sfd,&readfds);
//接收select返回值
int res=-1;
//接收recvfrom返回值
int count=0;
int index=0;
//发送消息容器
char buf[128]="";
//定义收发消息结构体
struct Msg recv_msg;
struct Msg send_msg;
while(1)
{
tempfds=readfds;
//检测集合中是否有事件发生
res=select(sfd+1,&tempfds,NULL,NULL,NULL);
if(res==0)
{
printf("time out\n");
return -1;
}else if(res==-1)
{
perror("select error");
return -1;
}
//接收到消息
if(FD_ISSET(sfd,&tempfds))
{
count=recvfrom(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&cin,&socklen);
if(count==-1)
{
perror("recvfrom error");
return -1;
}
//收到消息类型为登录型
if(recv_msg.type=='L')
{
//把当前客户端放入客户端数组下标为index的位置
arr_cin[index]=cin;
index++;
//上线格式
sprintf(buf,"---%s已上线---\n",recv_msg.name);
printf("%s\n",buf);
//把上线消息发送给其他客户端
for(int i=0;i<=index;i++)
{
//不发给发信息的客户端
if(arr_cin[i].sin_port==cin.sin_port)
{
continue;
}
sendto(sfd,&recv_msg,sizeof(recv_msg),0,(struct sockaddr*)&arr_cin[i],sizeof(arr_cin[i]));
}
}
//收到消息类型为聊天型
if(recv_msg.type=='C')
{
//把接收到的消息发给其他客户端
send_msg.type=recv_msg.type;
strcpy(send_msg.name,recv_msg.name);
strcpy(send_msg.text,recv_msg.text);
for(int i=0;i