Linux下c语言TCP多线程聊天室
开发环境:Linux,GCC
相关知识:TCP(博客:传送门),线程
附加:项目可能还有写不足之处,有些bug没调出来(如:对在线人数的控制),希望大佬赐教。
那么话不多说,放码过来:
服务端:server.c
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h> struct sockaddr_in addr = {};
int clifd_index = ; // clifd的下标
char buf[] = {}; // 存储客户端发来的字符串
char str[] = {}; // 存储带clifd的回传信息
int clifd[] = {}; // 存储clifd
int online_num = ; // 连接人数
int max_num = ; // 最大人数 // 项目有bug,连接人数的限制控制不住,有待改进 void* start_read(void *arg) // 读取信息的子线程
{
// printf("arg:%d\n",*(int*)arg);
int clifd1 = *(int*)arg;
printf("run_clifd:%d\n",clifd1); for(;;)
{
// printf("before read\n"); int ret = read(clifd1,buf,sizeof(buf));
printf("\nip:%s,port:%hu,size:%d\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port),ret); // 获取相关信息
printf("say:%s\n",buf); char id[] = {};
sprintf(id,"%d说:",clifd1); if(strlen(buf) != )
{
strcpy(str,id);
strcat(str,buf);
} // 存入str中 if( == strcmp("quit",buf)) // 如果收到quit
{
online_num--; // 在线人数-1
for(int i=; i<clifd_index; i++)
{
if(clifd1 == clifd[i])
{
int *die = &clifd1;
clifd[i] = ;
pthread_exit(die); // 终止线程
break;
}
}
}
//usleep(1000);
}
} void* start_write(void *arg) // 写回的子线程
{
// printf("arg:%d\n",*(int*)arg); // usleep(500); int clifd1 = *(int*)arg; printf("run_clifd:%d\n",clifd1); for(;;)
{
int flag = ;
for(int i=; i<clifd_index; i++) // 因为读到quit的原因,clifd被置0
{
if(clifd1 == clifd[i])
{
break;
}
if(i == clifd_index-)
{
int *die = &clifd1;
flag = ;
pthread_exit(die); // 终止此写回的子线程
}
}
if(flag == )
{
break;
} if(strlen(str) == ) // 空消息不写入
continue;
printf("before write\n");
printf("str:%s\n",str);
write(clifd1,str,strlen(str)+);
usleep(); // 最快的子线程等待其他子线程
memset(str,,); // 清空str
}
} int main()
{
printf("服务器创建socket...\n");
int sockfd = socket(AF_INET,SOCK_STREAM,);
if( > sockfd)
{
perror("socket");
return -;
} printf("准备地址...\n"); addr.sin_family = AF_INET;
addr.sin_port = htons();//端口号
addr.sin_addr.s_addr = inet_addr("10.0.2.15");//你的ip地址(或服务器的私网ip)
socklen_t len = sizeof(addr); printf("绑定socket与地址...\n");
if(bind(sockfd,(struct sockaddr*)&addr,len))
{
perror("bind");
return -;
} printf("设置监听...\n");
if(listen(sockfd,))
{
perror("listen");
return -;
} printf("等待客户端连接...\n");
for(;;)
{
if(online_num < max_num)
{
struct sockaddr_in addrcli = {};
clifd[clifd_index] = accept(sockfd,(struct sockaddr*)&addrcli,&len); int flag = ;
for(int i=; i<clifd_index; i++)
{
if(clifd[clifd_index] == clifd[i])
{
flag = ;
break;
}
} if(flag == )
{
clifd_index--;
continue;
}
else
{
char link[] = {};
char link1[] = "您已经成功连接";
sprintf(link,"您的id是:%d,",clifd[clifd_index]);
strcat(link,link1);
write(clifd[clifd_index],link,strlen(link)+);
online_num++;
}
}
else
{
continue;
} if( > clifd[clifd_index])
{
perror("accept");
continue;
} printf("clifd:%d\n",clifd[clifd_index]); // 创建子线程
pthread_t pid1,pid2;
pthread_create(&pid1,NULL,start_read,&clifd[clifd_index]);
pthread_create(&pid2,NULL,start_write,&clifd[clifd_index]); usleep(); // printf("clifd:%d\n",clifd[index]); clifd_index++; // 下标逐渐+1,这样写不是很合适 }
return ;
}
客户端:client.c
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h> void* start_read(void* arg) // 读取信息
{
int sockfd = *(int*)arg;
char buf[] = {};
for(;;)
{
read(sockfd,buf,sizeof(buf));
if(strlen(buf) != )
{
printf("\n>%s\n",buf);
}
}
} int main()
{
printf("服务器创建socket...\n");
int sockfd = socket(AF_INET,SOCK_STREAM,);
if( > sockfd)
{
perror("socket");
return -;
} printf("准备地址...\n");
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons();//设置的端口号
addr.sin_addr.s_addr = inet_addr("10.0.2.15");//你的ip地址(或服务器的公网ip)
socklen_t len = sizeof(addr); printf("绑定连接服务器...\n");
if(connect(sockfd,(struct sockaddr*)&addr,len))
{
perror("connect");
return -;
} char link[] = {};
read(sockfd,link,sizeof(link));
// printf("link:%s\n",link);
if(strstr(link,"您已经成功连接")==NULL)
{
printf("连接人数已满,请稍后重试\n");
return ;
}
else
{
printf("link:%s\n",link);
} // 创建读取子线程
pthread_t pid;
pthread_create(&pid,NULL,start_read,&sockfd); for(;;)
{
char buf[] = {};
usleep();
//printf(">我说:");
gets(buf);
write(sockfd,buf,strlen(buf)+);
if( == strcmp("quit",buf))
{
printf("通信结束!\n");
break;
}
} close(sockfd);
}
Linux下c语言TCP多线程聊天室的更多相关文章
- TCP多线程聊天室
TCP协议,一个服务器(ServerSocket)只服务于一个客户端(Socket),那么可以通过ServerSocket+Thread的方式,实现一个服务器服务于多个客户端. 多线程服务器实现原理— ...
- Linux以下基于TCP多线程聊天室(server)
接上篇博文,本文是server端的实现,主要实现的功能,就是现实client的连接.转发client发送的消息.以及client掉线提示等功能,同一时候能够在这这上面扩展和TCP以及线程相关的功能木块 ...
- Linux以下基于TCP多线程聊天室(client)
不怎么会弄这个博客的排版,就直接将代码附上: 主要是使用多线程去等待接受数据和发送数据.以下是client的代码: tcpsed.h文件 1 2 3 4 5 6 7 8 9 10 11 12 13 1 ...
- linux下c语言的多线程编程
我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 多线程的一些小知识: 一个应用程序可以启动若干个线程. 线程(Lightweight Process,LWP),是程序执 ...
- linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】
转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html 操作系统:ubuntu10.04 前言: 在嵌入式开发中,只要是带操作系统的 ...
- linux下c语言实现多线程文件复制【转】
转自:https://www.cnblogs.com/zxl0715/articles/5365989.html .具体思路 把一个文件分成N份,分别用N个线程copy, 每个线程只读取指定长度字节大 ...
- 基于Linux的TCP网络聊天室
1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...
- linux下C语言多线程编程实例
用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...
- linux 下C语言学习路线
UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...
随机推荐
- 类似hover的css伪类注解
a:link { font-size: 14pt; text-decoration: underline; color: blue; } /*设置a对象在未被访问前的样式表属性 .*/ a:hover ...
- sql的日期格式化转化
1. DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据. DATE_FORMAT(date,format) 可以使用的格式有: 格式 描述 %a 缩写星期名 %b 缩写月名 %c 月 ...
- shell脚本遇到问题"$'\r': command not found"
shell脚本写得一切正常,但是一执行就报错: line: XXX "$'\r': command not found" 问题原因:文件格式问题(虽然在window和linux上选 ...
- IntelliJ idea SpringBoot打war包
简单易用的使用idea 将SpringBoot工程打war包的方法 pom.xml中添加标签 1. 声明打包格式 <packaging>war</packaging> 2. ...
- Elasticsearch高版本安装head插件
安装Elasticsearch 1.安装Elasticsearch-6.5.4.tar.gz [merce@info5 ~]$ cd /appmerce/zrapp/ [merce@info5 zra ...
- [转]【response】HttpServletResponse接口
创建时间:6.19 & 6.24 1.HttpServletResponse概述 我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参 ...
- dapi 基于Django的轻量级测试平台四 任务设置
QQ群: GitHub:https://github.com/yjlch1016/dapi 一.间隔时间: 二.定时时间: 三.任务设置: 四.任务结果:
- 第03节-BLE协议各层数据格式概述
本篇博客根据韦大仙的视频,整理所得. 对于BLE系统,它分为上下两块.上面那一块,我们称为host主机.下面这一块是controller,你可以简单的认为它就是一个蓝牙芯片. 对于host这一块,它运 ...
- LCD硬件原理
想象一下,屏幕的后面有一个电子枪,电子枪位于某个像素的背后,然后向这个像素发射红绿蓝三原色,从而就可以组成任意一种颜色.简单的说,电子枪在像素的背后一边移动,一边向像素发射红绿蓝. 如果要编写出LCD ...
- Anaconda3(5-1)程序编辑器 自带的spyder
1装好后自带spyder编辑器 2 打开软件 3 每次程序需要制定anaconda3中创建的虚拟环境对应 的python版本的路径 例如在我的电脑我创建了两个环境 而我的pytorch安装在pytho ...