客户端
#include <myhead.h>
#define BUF_SIZE (4096)
void* client_read(void* arg)
{
int cli_fd = *(int*)arg;
char buf[BUF_SIZE];
//接受数据
for(;;)
{
int recv_size = read(cli_fd,buf,BUF_SIZE);
if(0 >= recv_size || 0 == strcmp(buf,"quit"))
{
printf("已经与服务器断开链接\n");
pthread_exit(NULL);
}
printf("%s\n",buf);
}
}
int main()
{
//创建socket对象
printf("创建socket对象...\n");
int cli_fd = socket(AF_INET,SOCK_STREAM,0);
if(0 > cli_fd)
{
perror("socket");
return -1;
}
//准备通信地址(服务端)
printf("准备通信地址...\n");
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(6789);
addr.sin_addr.s_addr = inet_addr("10.0.2.15");//此处填写自己的ip地址
socklen_t addrlen = sizeof(addr);
//链接服务端
printf("链接服务端口...\n");
if(connect(cli_fd,(struct sockaddr*)&addr,addrlen))
{
perror("connect");
return -1;
}
char buf[BUF_SIZE];
read(cli_fd,buf,BUF_SIZE);
if(NULL == strstr(buf,"链接成功"))
{
printf("群聊人已满,请稍后再来\n");
close(cli_fd);
return 0;
}
printf("%s\n",buf);
//链接成功,创建客户端
pthread_t tid;
pthread_create(&tid,NULL,client_read,&cli_fd);
//输入昵称
char name[BUF_SIZE] = {};
printf("请输入你的昵称:");
gets(name);
write(cli_fd,name,strlen(name)+1);
//发送数据
for(;;)
{
printf(">>");
gets(buf);
char msg[BUF_SIZE];
sprintf(msg,"%s:%s",name,buf);
int send_size = write(cli_fd,msg,strlen(msg)+1);
if(0 >= send_size || 0 == strcmp(buf,"quit"))
{
printf("结束通信\n");
close(cli_fd);
pthread_exit(NULL);
return 0;
}
}
}
服务器
#include <myhead.h>
#define BUF_SIZE (4096)
#define SEM_SIZE (5 ) //群聊上限人数
//信号量--判断群聊人数
sem_t sem;
//服务端文件描述符
int svr_fd;
//存储群友,多一个是为了当群人满时,空一个出来接发信息
int cli_fd[SEM_SIZE+1] = {};
//群发函数
void* send_all(char* buf)
{
for(int i=0; i<SEM_SIZE; i++)
{
//若值为-1,则没有此群友,表示已经退出或未被占有
if(-1 != cli_fd[i])
{
printf("%s\n",buf);
printf("send to %d\n",cli_fd[i]);
write(cli_fd[i],buf,strlen(buf)+1);
}
}
}
//服务端接收函数
void* server(void* arg)
{
int fd = *(int*)arg;
char buf[BUF_SIZE];
char name[BUF_SIZE],ts[BUF_SIZE];
//获取昵称
read(fd,name,sizeof(name));
sprintf(ts,"热烈欢迎 %s 进入群聊",name);
send_all(ts);
for(;;)
{
//接收信息
int recv_size = read(fd,buf,sizeof(buf));
//收到退出信息
if(0 >= recv || NULL != strstr(buf,"quit"))
{
sprintf(ts,"欢送 %s 离开群聊\n",name);
int index = 0;
//找到要退出的那个人,并将其置为-1
for(; index < SEM_SIZE; index++)
{
if(cli_fd[index] == fd)
{
cli_fd[index] = -1;
break;
}
}
send_all(ts);
//群友退出,信号量+1
int n;
sem_post(&sem);
sem_getvalue(&sem,&n);
printf("%s 离开群聊,群聊还剩%d人\n",name,SEM_SIZE-n);
strcpy(buf,"quit");
write(fd,buf,strlen(buf)+1);
close(fd);
pthread_exit(NULL);
}
send_all(buf);
}
}
void sigint(int signum)
{
close(svr_fd);
sem_destroy(&sem);
printf("服务器关闭\n");
exit(0);
}
int main()
{
signal(SIGINT,sigint);
//初始化信号量,群聊上限SEM_SIZE人
sem_init(&sem,0,SEM_SIZE);
//创建socket对象
printf("创建socket对象...\n");
svr_fd = socket(AF_INET,SOCK_STREAM,0);
if(0 > svr_fd)
{
perror("socket");
return -1;
}
//准备通信地址(自己)
printf("准备通信地址...\n");
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(6789);
addr.sin_addr.s_addr = inet_addr("10.0.2.15");
socklen_t addrlen = sizeof(addr);
//绑定socket对象与地址
printf("绑定socket对象与地址...\n");
if(bind(svr_fd,(struct sockaddr*)&addr,addrlen))
{
perror("bind");
return -1;
}
//设置监听和排除数量
printf("设置监听");
if(listen(svr_fd,10))
{
perror("listen");
return -1;
}
printf("等待客户端链接...\n");
//将初始值置全为-1,表示该聊天位置没有人占领
memset(cli_fd,-1,sizeof(cli_fd));
for(;;)
{
int sem_num;
sem_getvalue(&sem,&sem_num);
//找到没有人占领的聊天位
int index = 0;
while(-1 != cli_fd[index]) index++;
cli_fd[index] = accept(svr_fd,(struct sockaddr*)&addr,&addrlen);
if(0 > cli_fd[index])
{
perror("accept");
return -1;
}
char buf[BUF_SIZE];
if(0 >= sem_num)
{
printf("人数已满,%d号客户端链接失败\n",cli_fd[index]);
sprintf(buf,"人数已满,客户端链接失败");
write(cli_fd[index],buf,strlen(buf)+1);
close(cli_fd[index]);
cli_fd[index] = -1;
}
else
{
sem_trywait(&sem);
sem_getvalue(&sem,&sem_num);
char msg[BUF_SIZE] = {};
printf("%d号客户端链接成功,当前聊天人数%d人\n",cli_fd[index],SEM_SIZE-sem_num);
sprintf(msg,"客户端链接成功,当前聊天人数%d人\n",SEM_SIZE-sem_num);
write(cli_fd[index],msg,strlen(msg)+1);
//创建线程客户端
pthread_t tid;
pthread_create(&tid,NULL,server,&cli_fd[index]);
}
}
}