C语言实现简易网络聊天室

 更新时间:2021年06月30日 17:23:30   作者:菠萝小马哥  
这篇文章主要为大家详细介绍了C语言实现简易网络聊天室,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了C语言实现网络聊天室的具体代码,供大家参考,具体内容如下

业务逻辑:

1、客户端注册名字
2、告诉所有在线的客户端,XXX进入聊天室
3、新建一个线程为该客户端服务,随时接收客户端发送来的消息
4、当接收到一个客户端的消息时,向每一个客户端转发一份(群聊)
5、同时在线人数最多50人

任何客户端可以随意随时进入或退出客户端

服务端代码server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#ifndef DEBUG
 #define debug(format,...) {}
#else
 #define debug(format,...) \
 {\
  fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
  fprintf(stdout,format,##__VA_ARGS__);\
  fprintf(stdout,"\n");\
 }
#endif//DEBUG

#define error(format,...)\
{\
 fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
 fprintf(stdout,format,##__VA_ARGS__);\
 fprintf(stdout,":%m\n");\
 exit(EXIT_FAILURE);\
}

// 客户端最大连接数
#define CLIENT_MAX 50

// 服务器端口号
#define PORT 5566

// 缓冲区大小
#define BUF_SIZE 4096

// 重定义socket地址类型
typedef struct sockaddr* SP;

// 客户端结构体
typedef struct Client
{
 int sock;//socket 标识符
 pthread_t tid; //线程ID
 char name[20];
 struct sockaddr_in addr;
}Client;

// 定义50个存储客户端的结构变量
Client clients[50];

// 定义信号量用于限制客户端的数量
sem_t sem;

// 信号处理函数
void sigint(int num)
{
 for(int i=0; i<10; i++)
 {
  if(clients[i].sock)
  {
   pthread_cancel(clients[i].tid);//销毁线程
  }
 }
 debug("服务器退出!");
 exit(EXIT_SUCCESS);
}

void client_eixt(Client* client)
{
 sem_post(&sem);
 close(client->sock);
 client->sock = 0;
}

void client_send(Client* client,char* buf)
{
 size_t len = strlen(buf)+1;
 for(int i=0; i<CLIENT_MAX; i++)
 {
  if(clients[i].sock && clients[i].sock != client->sock)
  {
    send(clients[i].sock,buf,len,0);
  }
 }
}

void* run(void* arg)
{
 Client* client = arg;
 char buf[BUF_SIZE] = {};

 // 接收昵称
 int ret_size = recv(client->sock,client->name,20,0);
 if(0 >= ret_size)
 {
  client_eixt(client);
  return NULL;
 }

 // 通知其它客户端新人上线
 sprintf(buf,"!!!欢迎%s进入聊天室!!!",client->name);
 client_send(client,buf);
 for(;;)
 { 
  // 接收消息
  ret_size = recv(client->sock,buf,BUF_SIZE,0);
  if(0 >= ret_size || 0 == strcmp("quit",buf))
  {
   // 通知其它客户端退出
   sprintf(buf,"!!!%s退出聊天室!!!",client->name);
   client_send(client,buf);
   client_eixt(client);
   return NULL;
  }
  strcat(buf,":");
  strcat(buf,client->name);
  client_send(client,buf);
  debug(buf);
 }
}

int main(int argc,const char* argv[])
{
 signal(SIGINT,sigint);
 debug("注册信号处理函数成功!");

 sem_init(&sem,0,CLIENT_MAX);
 debug("初始化信号量成功!");

 int svr_sock = socket(AF_INET,SOCK_STREAM,0);
 if(0 > svr_sock)
 {
  error("socket");
 }
 debug("创建socket对象成功!");

 struct sockaddr_in svr_addr = {};
 svr_addr.sin_family = AF_INET;
 svr_addr.sin_port = htons(PORT);
 svr_addr.sin_addr.s_addr = INADDR_ANY;
 socklen_t addrlen = sizeof(svr_addr);
 debug("准备通信地址成功!");

 if(bind(svr_sock,(SP)&svr_addr,addrlen))
 {
  error("bind");
 }
 debug("绑定socket对象和通信地址成功!");


 if(listen(svr_sock,10))
 {
  error("listen");
 }
 debug("设置监听socket监听成功!");

 for(;;)
 {
  debug("等待客户端连接...");

  sem_wait(&sem);
  int index = 0;
  while(clients[index].sock)
  {
   index++;
  }

  clients[index].sock = accept(svr_sock,(SP)&clients[index].addr,&addrlen);
  if(0 > clients[index].sock)
  {
   kill(getpid(),SIGINT);
  }

  debug("有新的客户端连接,from ip:%s",inet_ntoa(clients[index].addr.sin_addr));
  pthread_create(&clients[index].tid,NULL,run,&clients[index]);
 }
}

客户端代码client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#ifndef DEBUG
 #define debug(format,...) {}
#else
 #define debug(format,...) \
 {\
  fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
  fprintf(stdout,format,##__VA_ARGS__);\
  fprintf(stdout,"\n");\
 }
#endif//DEBUG

#define error(format,...)\
{\
 fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
 fprintf(stdout,format,##__VA_ARGS__);\
 fprintf(stdout,":%m\n");\
 exit(EXIT_FAILURE);\
}

#define BUF_SIZE  4096
#define SERVER_PORT 5566
#define SERVER_IP  "192.168.0.125"
typedef struct sockaddr* SP;

void* run(void* arg)
{
 int cli_sock = *(int*)arg;
 char buf[BUF_SIZE] = {};
 for(;;)
 {
  int ret_size = recv(cli_sock,buf,BUF_SIZE,0);
  if(0 >= ret_size)
  {
   printf("服务器正在升级,请稍候登录!\n");
   exit(EXIT_SUCCESS);
  }
  printf("\r%30s\n>>>",buf);
  fflush(stdout);
 }
}


int main(int argc,const char* argv[])
{
 int cli_sock = socket(AF_INET,SOCK_STREAM,0);
 if(0 > cli_sock)
 {
  error("socket");
 }

 struct sockaddr_in cli_addr = {};
 cli_addr.sin_family = AF_INET;
 cli_addr.sin_port = htons(SERVER_PORT);
 cli_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
 socklen_t addrlen = sizeof(cli_addr);

 if(connect(cli_sock,(SP)&cli_addr,addrlen))
 {
  printf("服务器正在升级,请稍候登录!\n");
  return EXIT_SUCCESS;
 }

 char buf[BUF_SIZE] = {};
 printf("请输入你的眤称:");
 gets(buf);
 send(cli_sock,buf,strlen(buf)+1,0);

 pthread_t tid;
 pthread_create(&tid,NULL,run,&cli_sock);

 for(;;)
 {
  printf(">>>");
  gets(buf);
  send(cli_sock,buf,strlen(buf)+1,0);
  if(0 == strcmp("quit",buf))
  {
   printf("退出聊天室!\n");
   return EXIT_SUCCESS;
  }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解基于C++实现约瑟夫环问题的三种解法

    详解基于C++实现约瑟夫环问题的三种解法

    约瑟夫环问题是算法中相当经典的一个问题,其问题理解是相当容易的,并且问题描述有非常多的版本,并且约瑟夫环问题还有很多变形,通过这篇约瑟夫问题的讲解,一定可以带你理解透彻
    2021-06-06
  • C++之CNoTrackObject类和new delete操作符的重载实例

    C++之CNoTrackObject类和new delete操作符的重载实例

    这篇文章主要介绍了C++之CNoTrackObject类和new delete操作符的重载实例,是C++程序设计中比较重要的概念,需要的朋友可以参考下
    2014-10-10
  • 深入解析C++编程中的运算符重载

    深入解析C++编程中的运算符重载

    这篇文章主要介绍了C++编程中的运算符重载,运算符重载是C++入门学习中的基础知识,需要的朋友可以参考下
    2016-04-04
  • C++容器vector实现通讯录功能

    C++容器vector实现通讯录功能

    这篇文章主要为大家详细介绍了C++容器vector实现通讯录功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • 探索Visual C++下创建WPF项目的方法示例

    探索Visual C++下创建WPF项目的方法示例

    这篇文章主要介绍了探索Visual C++下创建WPF项目的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • C语言三子棋小游戏的实现代码

    C语言三子棋小游戏的实现代码

    这篇文章主要为大家详细介绍了C语言三子棋小游戏的实现代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • C语言的数字游戏算法效率问题探讨实例

    C语言的数字游戏算法效率问题探讨实例

    这篇文章主要介绍了C语言的数字游戏算法效率问题探讨实例,需要的朋友可以参考下
    2014-04-04
  • jquery ready函数深入分析

    jquery ready函数深入分析

    本文主要介绍jquery ready,这里整理了相关资料及相关示例代码帮助大家学习参考,有兴趣的小伙伴可以参考下
    2016-08-08
  • C++中结构体和Json字符串互转的问题详解

    C++中结构体和Json字符串互转的问题详解

    这篇文章主要给大家介绍了关于C++中结构体和Json字符串互转问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • C++实现LeetCode(44.外卡匹配)

    C++实现LeetCode(44.外卡匹配)

    这篇文章主要介绍了C++实现LeetCode(44.外卡匹配),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07

最新评论