开发环境:Linux,GCC

相关知识:TCP(博客:传送门),线程

附加:项目可能还有写不足之处,有些bug没调出来(如:对在线人数的控制),希望大佬赐教。

那么话不多说,放码过来:

码云:传送门,GitHub:传送门

服务端: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多线程聊天室的更多相关文章

  1. TCP多线程聊天室

    TCP协议,一个服务器(ServerSocket)只服务于一个客户端(Socket),那么可以通过ServerSocket+Thread的方式,实现一个服务器服务于多个客户端. 多线程服务器实现原理— ...

  2. Linux以下基于TCP多线程聊天室(server)

    接上篇博文,本文是server端的实现,主要实现的功能,就是现实client的连接.转发client发送的消息.以及client掉线提示等功能,同一时候能够在这这上面扩展和TCP以及线程相关的功能木块 ...

  3. Linux以下基于TCP多线程聊天室(client)

    不怎么会弄这个博客的排版,就直接将代码附上: 主要是使用多线程去等待接受数据和发送数据.以下是client的代码: tcpsed.h文件 1 2 3 4 5 6 7 8 9 10 11 12 13 1 ...

  4. linux下c语言的多线程编程

    我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 多线程的一些小知识: 一个应用程序可以启动若干个线程. 线程(Lightweight Process,LWP),是程序执 ...

  5. linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html 操作系统:ubuntu10.04 前言:     在嵌入式开发中,只要是带操作系统的 ...

  6. linux下c语言实现多线程文件复制【转】

    转自:https://www.cnblogs.com/zxl0715/articles/5365989.html .具体思路 把一个文件分成N份,分别用N个线程copy, 每个线程只读取指定长度字节大 ...

  7. 基于Linux的TCP网络聊天室

    1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...

  8. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  9. linux 下C语言学习路线

    UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...

随机推荐

  1. springboot入门介绍

    1. SpringBoot学习之@SpringBootApplication注解 下面是我们经常见到SpringBoot启动类代码: @SpringBootApplicationpublic clas ...

  2. elasticsearch安装中文分词器插件smartcn

    原文:http://blog.java1234.com/blog/articles/373.html elasticsearch安装中文分词器插件smartcn elasticsearch默认分词器比 ...

  3. yaml格式配置文件

    YAML 是一种可读性非常高,与程序语言数据结构非常接近.同时具备丰富的表达能力和可扩展性,并且易于使用的数据标记语言. python中处理 Yaml 格式的数据需要先下载pyyaml: pip in ...

  4. mysql--日志文件

    1 选择常规查询日志和慢查询日志输出目标 1.1  log_output查看.定义 所谓的输出目标就是日志写入到哪里,mysql中用系统变量 log_output来指定输出目标,log_output的 ...

  5. 阿里云 OSS文件存储挂到云服务器ESC文件系统中

    ossfs能让您在Linux系统中,将对象存储OSS的存储空间(Bucket)挂载到本地文件系统中,您能够像操作本地文件一样操作OSS的对象(Object),实现数据的共享. 使用限制 ossfs使用 ...

  6. PHP的SOLID设计原则

    SOLID Design Principles, 这是一个比设计模式更高级别的概念, 以构建良好代码为目标,真正掌握了就是大师级别了. 我~~~仅知晓~ /*SOLID Design Principl ...

  7. php模板模式(template design)

    没有写停止条件,所以会一直运行哟. <?php /* The template design pattern defines the program skeleton of an algorit ...

  8. java.time.format.DateTimeParseException: Text '2019-10-11 12:30:30' could not be parsed at index 10

    java.time.format.DateTimeParseException: Text '2019-10-11 12:30:30' could not be parsed at index 10 ...

  9. 201871010109-胡欢欢《面向对象程序设计(java)》第四周学习总结会

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  10. ES6新增的数组方法

    ES6新增:(IE9级以上支持) 1.forEach():遍历数组,无返回值,不改变原数组. 2.map():遍历数组,返回一个新数组,不改变原数组. 3.filter():过滤掉数组中不满足条件的值 ...