zoukankan      html  css  js  c++  java
  • 基于tcp和多线程的多人聊天室-C语言

    之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室。

    具体的实现过程:

      服务器端:绑定socket对象->设置监听数->等待连接->有客户端连接就新建一个线程,这个线程中,一旦就收到这个客户发送的消息,就广播的向其他客户端发送同样的消息。

      客户端:向客户端连接->新建线程用来接收服务器端发送的消息,同时主进程用来发送消息

    话不多说,直接上代码

      1 #include <stdio.h>
      2 #include <sys/types.h>
      3 #include <sys/socket.h>
      4 #include <pthread.h>
      5 #include <arpa/inet.h>
      6 #include <netinet/in.h>
      7 #include <string.h>
      8 #include <unistd.h>
      9 #include <stdlib.h>
     10 
     11 typedef struct sockaddr *sockaddrp;
     12 
     13 //存储客户端地址的结构体数组
     14 struct sockaddr_in src_addr[50];
     15 socklen_t src_len = sizeof(src_addr[0]);
     16 
     17 
     18 
     19 //连接后记录confd数组
     20 int confd[50] = {};
     21 
     22 
     23 //设置连接人数
     24 int count = 0;
     25 
     26 
     27 void *broadcast(void *indexp)
     28 {
     29     int index = *(int *)indexp;
     30     char buf_rcv[255] = {};
     31     char buf_snd[255] = {};
     32     //第一次读取用户姓名
     33     char name[20] = {};
     34     int ret = recv(confd[index],name,sizeof(name),0);
     35     if(0 > ret)
     36     {
     37         perror("recv");
     38         close(confd[index]);
     39         return;
     40     }
     41 
     42     while(1)
     43     {
     44         bzero(buf_rcv,sizeof(buf_rcv));
     45         recv(confd[index],buf_rcv,sizeof(buf_rcv),0);
     46 
     47         //判断是否退出
     48         if(0 == strcmp("quit",buf_rcv))
     49         {
     50             sprintf(buf_snd,"%s已经退出悟空聊天室",name);
     51             for(int i = 0;i <= count;i++)
     52             {
     53                 if(i == index || 0 == confd[i])
     54                 {
     55                     continue;
     56                 }
     57 
     58                 send(confd[i],buf_snd,strlen(buf_snd),0);
     59             }
     60             confd[index] = -1;
     61             pthread_exit(0);
     62                     
     63         }
     64 
     65 
     66         sprintf(buf_snd,"%s:%s",name,buf_rcv);
     67         printf("%s
    ",buf_snd);
     68         for(int i = 0;i <= count;i++)
     69         {
     70             if(i == index || 0 == confd[i])
     71             {
     72                 continue;
     73             }
     74 
     75             send(confd[i],buf_snd,sizeof(buf_snd),0);
     76         }
     77         
     78     }
     79 
     80 }
     81 
     82 
     83 
     84 
     85 
     86 int main(int argc,char **argv)
     87 {
     88     printf("悟空聊天室服务器端开始运行
    ");
     89 
     90 
     91     //创建通信对象
     92     int sockfd = socket(AF_INET,SOCK_STREAM,0);
     93     if(0 > sockfd)
     94     {
     95         perror("socket");
     96         return -1;
     97     }
     98 
     99     //准备地址
    100     struct sockaddr_in addr = {AF_INET};
    101     addr.sin_port = htons(atoi(argv[1]));
    102     addr.sin_addr.s_addr = inet_addr(argv[2]);
    103 
    104     socklen_t addr_len = sizeof(addr);
    105 
    106 
    107 
    108     //绑定
    109     int ret = bind(sockfd,(sockaddrp)&addr,addr_len);
    110     if(0 > ret)
    111     {
    112         perror("bind");
    113         return -1;
    114     }
    115 
    116 
    117     //设置最大排队数
    118     listen(sockfd,50);
    119 
    120     int index = 0;
    121 
    122 
    123     while(count <= 50)
    124     {
    125         confd[count] = accept(sockfd,(sockaddrp)&src_addr[count],&src_len);
    126         ++count;
    127         //保存此次客户端地址所在下标方便后续传入
    128         index = count-1;
    129 
    130         pthread_t tid;
    131         int ret = pthread_create(&tid,NULL,broadcast,&index);
    132         if(0 > ret)
    133         {
    134             perror("pthread_create");
    135             return -1;
    136         }
    137 
    138 
    139     }
    140 
    141 
    142 }
    server.c
      1 #include <stdio.h>
      2 #include <sys/types.h>
      3 #include <sys/socket.h>
      4 #include <arpa/inet.h>
      5 #include <netinet/in.h>
      6 #include <pthread.h>
      7 #include <string.h>
      8 
      9 
     10 
     11 typedef struct sockaddr *sockaddrp;
     12 int sockfd;
     13 
     14 void *recv_other(void *arg)
     15 {
     16     char buf[255]= {};
     17     while(1)
     18     {
     19         int ret = recv(sockfd,buf,sizeof(buf),0);
     20         if(0 > ret)
     21         {
     22             perror("recv");
     23             return;
     24         }
     25         printf("%s
    ",buf);
     26     }
     27 }
     28 
     29 
     30 
     31 
     32 int main(int argc,char **argv)
     33 {
     34     if(3 != argc)
     35     {
     36         perror("参数错误");
     37         return -1;
     38     }
     39 
     40     //建立socket对象
     41     sockfd = socket(AF_INET,SOCK_STREAM,0);
     42     if(0 > sockfd)
     43     {
     44         perror("socket");
     45         return -1;
     46     }
     47 
     48     //准备连接地址
     49     struct sockaddr_in addr = {AF_INET};
     50     addr.sin_port = htons(atoi(argv[1]));
     51     addr.sin_addr.s_addr = inet_addr(argv[2]);
     52 
     53     socklen_t addr_len = sizeof(addr);
     54 
     55 
     56     //连接
     57     int ret = connect(sockfd,(sockaddrp)&addr,addr_len);
     58     if(0 > ret)
     59     {
     60         perror("connect");
     61         return -1;
     62     }
     63 
     64     //发送名字
     65     char buf[255] = {};
     66     char name[255] = {};
     67     printf("请输入您的昵称:");
     68     scanf("%s",name);
     69     ret = send(sockfd,name,strlen(name),0);
     70     if(0 > ret)
     71     {
     72         perror("connect");
     73         return -1;
     74     }
     75 
     76     //创建接收子线程
     77     pthread_t tid;
     78     ret = pthread_create(&tid,NULL,recv_other,NULL);
     79     
     80     if(0 > ret)
     81     {
     82         perror("pthread_create");
     83         return -1;
     84     }
     85     //循环发送
     86     while(1)
     87     {
     88         //printf("%s:",name);
     89         scanf("%s",buf);
     90         int ret = send(sockfd,buf,strlen(buf),0);
     91         if(0 > ret)
     92         {
     93             perror("send");
     94             return -1;
     95         }
     96 
     97         //输入quit退出
     98         if(0 == strcmp("quit",buf))
     99         {
    100             printf("%s,您已经退出了悟空聊天室
    ",name);
    101             return 0;
    102         }
    103 
    104     }
    105 
    106 }
    client.c

    将两份代码分别编译生成相应可执行文件,例如在Linux下server,client,然后先执行./server 端口号 ip ,再执行./client 端口号 ip就可以运行这个聊天室了。

    总结:关于网络编程,tcp是一种连接方式的通信方式,两边一旦建立连接,就可以通过send和recv函数发送消息,比较的可靠,缺点是速度比较慢(相对于udp来说)。另外关于多线程编程方面,线程其实是一个进程的实体,是一个进程的组成部分,多个线程共享除了栈区以外的大部分区域,因此进程间的通信比较方便,这种方便带来的代价是,当多个进程同时去操作同一量时,容易造成不可预知的错误,因此就引入了互斥量(锁)的概念,互斥量的使用就保证了进程间通信的同步。

  • 相关阅读:
    10 个你需要了解的 Linux 网络和监控命令
    U盘安装 bt5
    SpringCloud RabbitMQ 使用
    两个大数相乘笔试题目
    activemq 话题模式(三)
    activemq 队列模式(二)
    activemq 安装 (一)
    安装mysql5.7时缺少my.ini文件
    linux 远程rsa 登录配置 文件 /etc/ssh/sshd_config
    java -jar 解决占用终端问题
  • 原文地址:https://www.cnblogs.com/LyndonMario/p/9435684.html
Copyright © 2011-2022 走看看