文档章节

基于tcp和多线程的多人聊天室-C语言

o
 osc_4nmshwhm
发布于 2018/08/07 10:52
字数 1264
阅读 19
收藏 0

精选30+云产品,助力企业轻松上云!>>>

之前在学习关于网络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\n",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("悟空聊天室服务器端开始运行\n");
 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\n",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,您已经退出了悟空聊天室\n",name);
101             return 0;
102         }
103 
104     }
105 
106 }
client.c

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

 

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

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
Python第四周之网络编程TCP (服务器/客户端; 线程下载图片;线程版服务器和客户端(单人、多人)) UDP

网络编程 # 计算机网络, 把多台独立自主的计算机,连接到网络,实现资源的共享 # Internet网,(互联网)eniac 1946美国大学第一台电子计算机 # # 一个TCP报文除了包含要传输的数据外,还包...

osc_kf729ara
2018/03/24
1
0
多人聊天室(Java)

第1部分 TCP和UDP TCP:是一种可靠地传输协议,是把消息按一个个小包传递并确认消息接收成功和正确才发送下一个包,速度相对于UDP慢,但是信息准确安全;常用于一般不要求速度和需要准确发送...

osc_kfnbvkb9
2019/03/21
8
0
Java网络编程案例---聊天室

  网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。   java.net包中JavaSE的API包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,...

osc_gni094m4
2019/04/05
19
0
c++实现服务器和多个客户端的实时群聊通信

我们通过TCP/IP来实现多人聊天室,如果租一个服务器我们就可以实现全网的多人聊天室(不懂tcp/ip的点进来https://www.cnblogs.com/yskn/p/9335608.html)!首先我们要了解一下一些知识: 1.sock...

osc_kt288isk
2018/07/23
5
0
17个C语言可以做的小案例项目

  C语言是我们大多数人的编程入门语言,对其也再熟悉不过了,不过很多初学者在学习的过程中难免会出现迷茫,比如:不知道C语言可以开发哪些项目,可以应用在哪些实际的开发中……,这些迷茫...

osc_778cbd0y
2018/05/06
28
0

没有更多内容

加载失败,请刷新页面

加载更多

JIT的Profile神器JITWatch

点击上方的蓝字关注我吧 程序那些事 简介 老是使用命令行工具在现代化社会好像已经跟不上节奏了,尤其是在做JIT分析时,使用LogCompilation输出的日志实在是太大了,让人望而生畏。有没有什么...

flydean
07/04
0
0
运维基础--虚拟机的使用(一)

虚拟机的使用 开始使用Linux操作系统时,首先可能会接触到两个主要的界面:GUI和CLI,即图形界面个命令界面,而运维一般极少使用到图形界面。 一、命令提示符的格式:[root@mylab11~] # roo...

osc_9os5791s
15分钟前
15
0
以程序员的方式,尽绵薄之力

作为程序员,我们不能冲在第一线,参与病毒防疫工作,我们希望通过我们的方式,让更多的人获取到关于疫情的有用的消息,正确的消息 虽然github可能是个相对小众的平台,对于非程序员来说,可...

Jipson
01/26
17
0
Oracle 等待事件之 db file scattered read

db file scattered read 官网解释: This event signifies that the user process is reading buffers into the SGA buffer cache and is waiting for a physical I/O call to return. A db......

osc_qlj7m2h9
16分钟前
19
0
互联网+时代的畅想

封面的台风卫星照片,我认为很形象地可以看作互联网的那一波浪潮。在智能手机普及的初始阶段,还记得我们对于互联网的狂热,有人说要用互联网颠覆一切,亦有人要用互联网干一切事情,当然,这...

zd200572
2015/09/02
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部