开发环境: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. 你家的APS系统有这些功能吗?排程系统功能盘点

    随着企业规模不断扩大,在经营管理方面会面临各种各样的问题,为了帮助解决此类问题,很多公司都会引入APS高级排程系统帮助进行生产管理的优化. APS系统针对的管理目标是 改善库存控制,大幅降低原料与中间 ...

  2. 外汇盈利EA

    >>>>>>>>>>>>>>>>>>>>>>>>> ...

  3. Lua 字符串查找函数 string.find(s, pattern [, init [, plain]] )【转】

    函数原型 string.find(s, pattern [, init [, plain]] ) s: 源字符串 pattern: 待搜索模式串 init: 可选, 起始位置 plain: 我没用过 ...

  4. Django学习之十四:Django ORM继承关系

    目录 Django ORM继承关系 1. SINGLE_TABLE(django好像不支持) 2. TABLE_PER_CLASS 3. JOINED 4. 代理继承 Django ORM继承关系 参 ...

  5. 解决debugJDK源码看不到局部变量的值

    背景:使用的jdk1.8.0_201 问题描述:在eclispe中调试代码进入到JDK源码中,想看到某个变量的值得变化,发现此变量的值没法看到 解决方案: 1.进入到你安装本机的jdk目录下,找到sr ...

  6. MySQL基本库表管理

    基本管理指令 mysql登陆 第一种 [root@wei ~]# mysql -u root -p 第二种(带参输入) [root@wei ~]# mysql -uroot -proot 注意:每个命 ...

  7. windows打印机服务自动关闭解决方案

    先点击右键点属性,启动方式选自动,然后(1)删除 C:\WINDOWS\system32\spool\PRINTERS 目录下的所有文件.(2)删除注册表 \HKEY_LOCAL_MACHINE\SY ...

  8. Android端项目测试

    目录 一.概述 二.使用工具 三.测试 1.测试主要的两大功能 进入主界面,测试排行榜查看功能是否能运行 测试83端口打卡能否运行 修改个人信息已经注册功能 2.测试参数是否正确 3.测试刷新能否使用 ...

  9. Codeforces G. The Brand New Function(枚举)

    题目描述: The Brand New Function time limit per test 2 seconds memory limit per test 256 megabytes input ...

  10. 使用BCP从Sybase远程数据库中导出数据

    1.在本机安装Sybase ASE 15,我装的开发版全套,懒得去仔细看需要哪个了 2.在Sybase安装目录里找到ini\sql.ini,在里面添加数据源例如: [MYDS] master=NLWN ...