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

具体的实现过程:

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

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

话不多说,直接上代码

 #include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h> typedef struct sockaddr *sockaddrp; //存储客户端地址的结构体数组
struct sockaddr_in src_addr[];
socklen_t src_len = sizeof(src_addr[]); //连接后记录confd数组
int confd[] = {}; //设置连接人数
int count = ; void *broadcast(void *indexp)
{
int index = *(int *)indexp;
char buf_rcv[] = {};
char buf_snd[] = {};
//第一次读取用户姓名
char name[] = {};
int ret = recv(confd[index],name,sizeof(name),);
if( > ret)
{
perror("recv");
close(confd[index]);
return;
} while()
{
bzero(buf_rcv,sizeof(buf_rcv));
recv(confd[index],buf_rcv,sizeof(buf_rcv),); //判断是否退出
if( == strcmp("quit",buf_rcv))
{
sprintf(buf_snd,"%s已经退出悟空聊天室",name);
for(int i = ;i <= count;i++)
{
if(i == index || == confd[i])
{
continue;
} send(confd[i],buf_snd,strlen(buf_snd),);
}
confd[index] = -;
pthread_exit(); } sprintf(buf_snd,"%s:%s",name,buf_rcv);
printf("%s\n",buf_snd);
for(int i = ;i <= count;i++)
{
if(i == index || == confd[i])
{
continue;
} send(confd[i],buf_snd,sizeof(buf_snd),);
} } } int main(int argc,char **argv)
{
printf("悟空聊天室服务器端开始运行\n"); //创建通信对象
int sockfd = socket(AF_INET,SOCK_STREAM,);
if( > sockfd)
{
perror("socket");
return -;
} //准备地址
struct sockaddr_in addr = {AF_INET};
addr.sin_port = htons(atoi(argv[]));
addr.sin_addr.s_addr = inet_addr(argv[]); socklen_t addr_len = sizeof(addr); //绑定
int ret = bind(sockfd,(sockaddrp)&addr,addr_len);
if( > ret)
{
perror("bind");
return -;
} //设置最大排队数
listen(sockfd,); int index = ; while(count <= )
{
confd[count] = accept(sockfd,(sockaddrp)&src_addr[count],&src_len);
++count;
//保存此次客户端地址所在下标方便后续传入
index = count-; pthread_t tid;
int ret = pthread_create(&tid,NULL,broadcast,&index);
if( > ret)
{
perror("pthread_create");
return -;
} } }

server.c

 #include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h> typedef struct sockaddr *sockaddrp;
int sockfd; void *recv_other(void *arg)
{
char buf[]= {};
while()
{
int ret = recv(sockfd,buf,sizeof(buf),);
if( > ret)
{
perror("recv");
return;
}
printf("%s\n",buf);
}
} int main(int argc,char **argv)
{
if( != argc)
{
perror("参数错误");
return -;
} //建立socket对象
sockfd = socket(AF_INET,SOCK_STREAM,);
if( > sockfd)
{
perror("socket");
return -;
} //准备连接地址
struct sockaddr_in addr = {AF_INET};
addr.sin_port = htons(atoi(argv[]));
addr.sin_addr.s_addr = inet_addr(argv[]); socklen_t addr_len = sizeof(addr); //连接
int ret = connect(sockfd,(sockaddrp)&addr,addr_len);
if( > ret)
{
perror("connect");
return -;
} //发送名字
char buf[] = {};
char name[] = {};
printf("请输入您的昵称:");
scanf("%s",name);
ret = send(sockfd,name,strlen(name),);
if( > ret)
{
perror("connect");
return -;
} //创建接收子线程
pthread_t tid;
ret = pthread_create(&tid,NULL,recv_other,NULL); if( > ret)
{
perror("pthread_create");
return -;
}
//循环发送
while()
{
//printf("%s:",name);
scanf("%s",buf);
int ret = send(sockfd,buf,strlen(buf),);
if( > ret)
{
perror("send");
return -;
} //输入quit退出
if( == strcmp("quit",buf))
{
printf("%s,您已经退出了悟空聊天室\n",name);
return ;
} } }

client.c

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

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

基于tcp和多线程的多人聊天室-C语言的更多相关文章

  1. 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室

    原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  2. 66 网络编程(五)——TCP多线程实现多人聊天室

    思路 客户端读写各一个类,可以使内部类,实现Runnable.读写类都与服务器端建立连接,一个收,一个发. 客户端实现接收和转发.多线程实现每个客户端的连接(使与各客户端的连接独立). 服务器端中创建 ...

  3. Python编写基于socket的非阻塞多人聊天室程序(单线程&多线程)

    前置知识:socket非阻塞函数(socket.setblocking(False)),简单多线程编程 代码示例: 1. 单线程非阻塞版本: 服务端: #!/usr/bin/env python # ...

  4. 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  5. java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端

    java 通过TCP\UDP 协议实现多人聊天,点对点,文件传送-----分服务器端和客户端 启动界面如下图: 首先启动服务器: 客户端登陆,登陆成功后为: 默认发送是全部用户,是多人发送. 当在边列 ...

  6. 多人聊天室(Java)

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

  7. Apache MiNa 实现多人聊天室

    Apache MiNa 实现多人聊天室 开发环境: System:Windows JavaSDK:1.6 IDE:eclipse.MyEclipse 6.6 开发依赖库: Jdk1.4+.mina-c ...

  8. Python实现网络多人聊天室

    网络多人聊天室 文件结构: chatroom ├── client.py  # 客户端代码 ├── language.py  # 语言文件 ├── server.py  # 服务端代码 └── set ...

  9. Python实现网络多人聊天室 - Windows

    项目名称:多人聊天室项目结构: client.py server.py settings.py项目思路:服务端接收客户端连接,客户端发送信息给服务端,服务端将信息发送给所有客户端.项目实现:主进程负责 ...

随机推荐

  1. Lotto HDU

    链接 [http://acm.hdu.edu.cn/showproblem.php?pid=1342] 题意 分析 DFS 代码 #include<cstdio> #include< ...

  2. 【Beta阶段】第十次Scrum Meeting!!!

    每日任务内容: 本次会议为第十次Scrum Meeting会议~ 本次会议为团队Beta阶段的最后一次会议!! 队员 今日完成任务 刘乾 #136(完成一半,今晨发布) 团队博客撰写 https:// ...

  3. SSM(Spring +SpringMVC + Mybatis)框架搭建

    SSM(Spring +SpringMVC + Mybatis)框架的搭建 最近通过学习别人博客发表的SSM搭建Demo,尝试去搭建一个简单的SSMDemo---实现的功能是对用户增删改查的操作 参考 ...

  4. Maven的课堂笔记4

    9.Maven与MyEclipse2014结合 MyEclipse10以上的版本,对Maven支持的就比较好 9.2 Myeclipse配置 本地文件夹的C盘的.m2文件夹下必须得有这个setting ...

  5. MySQL: Connection Refused,调整 mysql.ini中的 max_connections

    连接相同的结构的MySQL数据库,一套库Tomcat启动正常,另一套库一直报Connection Refused. 可以断定是连接数太小了.查找mysql.ini中的 max_connections, ...

  6. Jfrog Artifactory 创建docker 镜像仓库以及 push 镜像到 该仓库.

    1. 安装aitifactory 以及 启动 使用30天有效期激活 不在阐述. 2. 登录artifactory username:admin password:password 3. 创建 仓库 在 ...

  7. [转帖] infiniband的协议速度

  8. 《spark快速大数据分析》

    第一 概论 1.spark的特点 适用多种不同分布式平台的场景,包括批处理,迭代算法,交互式查询,流处理: spark提供了python,scale,java等接口 2.spark的组件 spark的 ...

  9. Spark_RDD之简单Java函数接口

    函数名 实现的方法 用途 Function<T, R> R call(T) 接收一个输入值并返回一个输出值,用于类似 map() 和filter() 等操作中 Function2<T ...

  10. Codeforces Round #428 (Div. 2)A,B,C

    A. Arya and Bran time limit per test 1 second memory limit per test 256 megabytes input standard inp ...