开发环境: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. 不要在 MySQL 中使用“utf8”,请使用“utf8mb4”

    不要在 MySQL 中使用“utf8”,请使用“utf8mb4” 最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串,然后出现了一个离奇的错误: ...

  2. HTML惊天地

    博主网站 一.HTML文档结构 <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  3. Generate a document using docxtemplater

    生成word文档,更新word内容 http://javascript-ninja.fr/docxtemplater/v1/examples/demo.html   https://docxtempl ...

  4. android studio学习----如何创建一个库项目

    首先,打开Android studio的软件工具,进入到界面中点击菜单的“file”选项. 2 在弹出的下拉的菜单中,可以看到的是为"New Module“的选项点击进入.   3 进入到c ...

  5. JVM性能优化简介

    01. JVM是什么    概述:        大白话:             全称Java Virtual Machine(Java虚拟机), 它是一个虚构出来的计算机, 通过实际的计算机来模拟 ...

  6. java基本类型的长度

    bit:位,一个二进制数据(0或者1),是1bit byte:字节,存储空间的基本单位,1byte=8bit 一个英文占一个字节,1字母=1byte=8bit 一个中文占两个字节,1汉字=2byte= ...

  7. cephfs测试中出现的问题

    最近重新对cephfs进行性能测试. 测试步骤: (1) 选取一个特地版本的操作系统内核,挂载20000个客户端; (2) 用iozone中的fileop工具,在每隔挂载点上都跑一个fileop进程; ...

  8. Nginx 高级配置-第三方模块编译

    Nginx 高级配置-第三方模块编译 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 第三模块是对nginx 的功能扩展,第三方模块需要在编译安装Nginx 的时候使用参数--add ...

  9. tensorflow运行时错误:服务似乎挂掉了,但是会立刻重启的.

    以前在POD里跑起来,没问题的示例代码. 移到jupyter中,多给两个GPU,有时运行就会爆出这个错误: 于是,按网上的意见,暂时加了个使用GPU的指定, 暂时搞定. 如下红色部分. import ...

  10. django rest framework 解析器组件 接口设计,视图组件 (2)

    1. 使用视图组件进行接口优化 1.1 使用视图组件的mixin进行接口逻辑优化 - 导入mixin from rest_framework.mixinx import ( ListModelMix, ...