项目需求:
- 如果有用户登录,其他用户可以收到这个人的登录信息
- 如果有人发送信息,其他用户可以收到这个人的群聊信息
- 如果有人下线,其他用户可以收到这个人的下线信息
- 服务器可以发送系统信息
服务器端
#include <myhead.h>
#define PORT 11111
#define IP "192.168.60.75"
//客户端结构体
typedef struct
{
struct sockaddr_in addr;
char name[20];//客户端姓名
int active;//标志位,确定客户端状态,0下线,1在线
}client;
client clients[50];
//服务器线程处理服务器广播
void *fun(void *oldfd)
{
int fd = *(int *)oldfd;
char buff[1024];
while(1)
{
char msg[1024];
bzero(buff,sizeof(buff));
fgets(buff,sizeof(buff),stdin);
msg[strlen(msg)-1]='\0';
sprintf(msg,"服务器消息:%s",buff);
for(int i=0;i<50;i++)
{
if(clients[i].active)
{
sendto(fd,msg,sizeof(msg),0,(struct sockaddr *)&clients[i].addr,sizeof(clients[i].addr));
}
}
}
}
int main(int argc, const char *argv[])
{
//创建udp套接字
int oldfd = socket(AF_INET,SOCK_DGRAM,0);
if(oldfd==-1)
{
perror("socket");
return -1;
}
//绑定套接字
struct sockaddr_in server = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = inet_addr(IP),
};
if(bind(oldfd,(struct sockaddr *)&server,sizeof(server))==-1)
{
perror("bind");
return -1;
}
printf("聊天室服务器启动,监听端口:%d\n",PORT);
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int client_count=0;
char buff[1024];
//服务器广播发送消息线程
pthread_t tid;
tid = pthread_create(&tid,NULL,fun,&oldfd);
if(tid==-1)
{
perror("pthread_create");
return -1;
}
while(1)
{
memset(buff,0,sizeof(buff));
//接收消息
int len = recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&client,&client_len);
//添加新客户端
if(len>0)
{
if(buff[0]=='L')
{
//检查客户端是否已经存在
int found=0;
for(int i=0;i<client_count;i++)
{
if(clients[i].addr.sin_addr.s_addr == client.sin_addr.s_addr &&
clients[1].addr.sin_port == client.sin_port)
{
found = 1;
printf("该用户已登录\n");
break;
}
}
//确保是新用户且服务器数量没有超过最大预设值
if(!found && client_count < 50)
{
//将active空置的客户端结构体存放新客户端信息
for(int i=0;i<=client_count;i++)
{
if(clients[i].active==0)
{
clients[i].addr = client;
strncpy(clients[i].name,buff+1,19);
clients[i].active = 1;
break;
}
}
//广播用户登录消息
char login[1024];
sprintf(login,"系统消息:%s加入聊天室",clients[client_count].name);
for(int i=0;i<client_count;i++)
{
if(clients[i].active)
{
sendto(oldfd,login,sizeof(login),0,(struct sockaddr *)&clients[i].addr,sizeof(clients[i].addr));
}
}
client_count++;
}
}
else if(buff[0]=='M')
{
//转发消息给其他用户
printf("%s\n",buff+1);//客户端输出消息
for(int i=0;i<client_count;i++)
{
//转发给在线的用户,且不转发给发送消息的客户端
if(clients[i].active && (clients[i].addr.sin_addr.s_addr != client.sin_addr.s_addr ||
clients[i].addr.sin_port != client.sin_port))
{
sendto(oldfd,buff+1,sizeof(buff)-1,0,(struct sockaddr *)&clients[i].addr,sizeof(clients[i].addr));
}
}
}
else if(buff[0]=='Q')
{
//客户端广播退出消息
for(int i=0;i<client_count;i++)
{
if(clients[i].addr.sin_addr.s_addr == client.sin_addr.s_addr &&
clients[i].addr.sin_port == client.sin_port)
{
clients[i].active = 0;
char quit[1024];
sprintf(quit,"系统消息:%s离开了聊天室",clients[i].name);
for(int j=0;j<client_count;j++)
{
if(clients[j].active)
{
sendto(oldfd,quit,sizeof(quit),0,(struct sockaddr *)&clients[j].addr,sizeof(clients[j].addr));
}
}
break;
}
}
}
}
}
return 0;
}
客户端
#include <myhead.h>
#define IP "192.168.60.75"
#define PORT 11111
void *message(void *oldfd)
{
int fd = *(int *)oldfd;
char buff[1024];
while(1)
{
bzero(buff,sizeof(buff));
if(recvfrom(fd,buff,sizeof(buff),0,NULL,NULL)>0)
{
printf("%s\n",buff);
}
}
exit(0);
}
int main(int argc, const char *argv[])
{
//创建套接字
int oldfd = socket(AF_INET,SOCK_DGRAM,0);
if(oldfd==-1)
{
perror("socket");
return -1;
}
struct sockaddr_in server = {
.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = inet_addr(IP),
};
//输入用户名
char name[20];
printf("请输入用户名:");
fgets(name,sizeof(name),stdin);
name[strlen(name)-1]='\0';
//发送登录消息
char buff[1024];
buff[0]='L';
strcpy(buff+1,name);
sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&server,sizeof(server));
//创建接收消息的线程
pthread_t tid;
tid = pthread_create(&tid,NULL,message,&oldfd);
if(tid==-1)
{
perror("pthread_create");
return -1;
}
//循环处理发送消息
while(1)
{
char msg[1024];
bzero(msg,sizeof(msg));
fgets(msg+1,sizeof(msg)-1,stdin);
//msg[strlen(msg)-1]='\0';
//退出客户端
if(strcmp(msg+1,"quit\n")==0)
{
printf("1\n");
msg[0]='Q';
msg[strlen(msg)-1] = '\0';
sendto(oldfd,msg,sizeof(msg),0,(struct sockaddr *)&server,sizeof(server));
break;
}
else
{
//发送消息
msg[0]='M';
char infor[1024];
sprintf(infor,"%s:%s",name,msg+1);
strcpy(msg+1,infor);
sendto(oldfd,msg,sizeof(msg),0,(struct sockaddr *)&server,sizeof(server));
}
}
close(oldfd);
return 0;
}
运行效果