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

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

具体的实现过程:

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

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

话不多说,直接上代码

2b65ef29a5872cc0e4771c25889edd04.gif

6a087676c59fa8b19d76e6bb55a32902.gif

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

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

2b65ef29a5872cc0e4771c25889edd04.gif

6a087676c59fa8b19d76e6bb55a32902.gif

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8

9

10

11 typedef struct sockaddr *sockaddrp;12 intsockfd;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来说)。另外关于多线程编程方面,线程其实是一个进程的实体,是一个进程的组成部分,多个线程共享除了栈区以外的大部分区域,因此进程间的通信比较方便,这种方便带来的代价是,当多个进程同时去操作同一量时,容易造成不可预知的错误,因此就引入了互斥量(锁)的概念,互斥量的使用就保证了进程间通信的同步。

原文:https://www.cnblogs.com/LyndonMario/p/9435684.html

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、 系统概要 1、 开发平台: Windows XP, Visual C++ 6.0 2、 系统简单描述: 这是一个用VC做的简单的聊天系统。在此系统中,采用TCP协议,程序分为服务器端各客户端。系统能实现简单的聊天室功能包括一对多,而且同时也支持一对一,即私聊功能。在系统运行中,用户可以随时更改自己的用户名。功能虽然单一但也能够满足聊天的基本功能。 二、 通信规范的制作 程序中定义了一个结构体MYMESSAGE来作为信息传送的载体 struct MESSAGE { char flag; //作为标志来区别所发送的信息; char data[100];//发送的内容; char addr[25]; //客户IP地址和端口号 }; 三、 主要模块的设计分析 服务器端: 系统流程如下: 设计思路: 基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序一般分为服务器端和用户端两部分。设计思路(VC6.0下): 第一部分 服务器端 一、创建服务器套接字(create)。 二、服务器套接字进行信息绑定(bind),并开始监听连接(listen)。 三、接受来自用户端的连接请求(accept)。 四、开始数据传输(send/receive)。 五、关闭套接字(closesocket)。 第二部分 客户端 一、创建客户套接字(create)。 二、与远程服务器进行连接(connect),如被接受则创建接收进程。 三、开始数据传输(send/receive)。 四、关闭套接字(closesocket)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值