1.实验项目名称:基于Linux的TCP网络聊天室

2.实验目的:通过TCP完成多用户群聊和私聊功能。

3.实验过程:

通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用多线程来实现多用户模式,服务器端随时准备接收客户端发送的消息,并判断该消息类型(私聊或群聊)来进行对应的转发工作,客户端随时接受来自服务器端的消息,从而实现消息的同步。

(1)开启服务器。

(2)开启客户端,输入用户昵称,客户端开始与服务器建立连接。

(3)群聊功能,一名用户发送消息,聊天室的其他成员均可收到此消息。

(4)私聊功能,一位用户@其他用户,则此消息只有被@的用户可以收到。

用户的信息借助结构体来存放,群聊功能通过遍历结构体,把消息发送给每一名用户,私聊功能通过对用户所发消息进行判断,若消息中存在@其他用户则把该消息私发给指定用户。

另外,私聊功能函数可以进行对各种@操作的判断,如用户所@的人不存在,则把此消息作为群消息发出,@其他用户后没有添加空格,则把此消息视为群发消息。

源码:

头文件

 1 //header.h
2 #ifndef _A_H
3 #define _A_H
4 #include <stdio.h>
5 #include <pthread.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <pthread.h>
14 struct client{
15 char name[30]; //客户端名字
16 int fds; //客户端socket描述符
17 };
18 struct client c[100]={0};//接收客户端100个
19 int in; //数组下标
20 char *IP ="127.0.0.1"; //ip
21 short PORT=10222;
22 char NAME[20]={}; //@的名字
23 int FLAG=0; //标记是群发还是私聊
24 #endif

服务器端

 1 //tcp_s.c
2 #include "header.h"
3 int sockfd; //服务器socket
4 char tempName[20]={};
5 //初始化服务器网络
6 void init(){
7 printf("start chat room...");
8 sockfd = socket(PF_INET,SOCK_STREAM,0);
9 if(sockfd == -1){
10 perror("create socket false\n");
11 exit(-1);
12 }
13 struct sockaddr_in addr; //网络通信地址结构
14 addr.sin_family = PF_INET; //协议簇
15 addr.sin_port = htons(PORT); //端口
16 addr.sin_addr.s_addr = inet_addr(IP); //IP地址
17 if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) == -1){
18 perror("bind false\n");
19 exit(-1);
20 }
21 if(listen(sockfd,100) == -1){
22 perror("Setup listening failed\n");
23 exit(-1);
24 }
25 printf("Server initialization succeeded!\n");
26 }

分发消息

 1 void SendMessage(char *msg){
2 int flag=0; //标记@符号是否为私聊
3 int exit=0; //比较@的用户是否存在
4 int i=0,j=0;
5 while(msg[i]!=':'){
6 if(i>=strlen(msg))
7 break;
8 i++;
9 } //找到@符号位置
10 if(msg[i+1] == '@'){
11 i++;
12 while(msg[i]!=32){
13 if(i>=strlen(msg)){ //@符号不是私聊作用
14 flag=1;
15 break;
16 }
17 NAME[j]=msg[i+1];
18 i++;
19 j++;
20 }
21 if(flag){ //群发
22 for(i=0;i<in;i++){
23 printf("send to %d\n",c[i].fds);
24 send(c[i].fds,msg,strlen(msg),0);
25 }
26 }
27 else{ //私发
28 for(i=0;i<in;i++){
29 int k=0;
30 for(k=0;k<strlen(NAME)-1;k++){
31 tempName[k]=NAME[k];
32 }
33 if(strcmp(c[i].name,tempName)==0){
34 send(c[i].fds,msg,strlen(msg),0);
35 exit=1;
36 break;
37 }
38 }
39 }
40 }
41 else{
42 exit = 1;
43 for(i=0;i<in;i++){
44 printf("send to %d\n",c[i].fds);
45 send(c[i].fds,msg,strlen(msg),0);
46 }
47 }
48 if(exit == 0){
49 for(i=0;i<in;i++){
50 printf("send to %d\n",c[i].fds);
51 send(c[i].fds,msg,strlen(msg),0);
52 }
53 }
54 }

线程函数中进行通信/接收客户端消息,分发给所有客户端 

 1 void *server_thread(void *p){
2 char name[30]={};
3 if(recv(c[in].fds,name,sizeof(name),0)>0){
4 name[strlen(name)]='\0';
5 strcpy(c[in].name,name);
6 }
7 in++;
8 char tip[100]={};
9 sprintf(tip,"%s join in the chat room\n",c[in-1].name);
10 SendMessage(tip);
11 int fd = *(int*)p;
12 printf("pthread = %d\n",fd);
13 while(1){
14 char buf[100]={};
15 if(recv(fd,buf,sizeof(buf),0) == 0){
16 //表示退出连接
17 printf("fd = %d left the chat room\n",fd);
18 int i,j;
19 char name[20]={};
20 int flag = 1;
21 for(i=0;i<in;i++){
22 if(c[i].fds == fd){
23 strcpy(name,c[i].name);
24 i++;
25 flag = 0;
26 }
27 if(flag != 1){
28 c[i-1].fds = c[i].fds;
29 strcpy(c[i-1].name,c[i].name);
30 }
31 }
32 c[i].fds = 0;
33 strcpy(c[i].name,"");
34 in--;
35 char msg[100];
36 sprintf(msg,"%s left the chat room\n",name);
37 SendMessage(msg);
38 close(fd);
39 break;
40 }
41 SendMessage(buf);
42 }
43 }

等待客户端连接,启动服务器的服务

 1 void server(){
2 printf("Server starts service!\n");
3 while(1){
4 struct sockaddr_in fromaddr; //存储客户端通信地址
5 socklen_t len = sizeof(fromaddr);
6 int fd = accept(sockfd,(struct sockaddr*)&fromaddr,&len);
7 if(fd == -1){
8 perror("Client connection failed!\n");
9 continue;
10 }
11 c[in].fds = fd;
12 pthread_t pid;
13 pthread_create(&pid,0,server_thread,&fd);
14 }
15 }
16 void sig_close(){
17 close(sockfd);
18 printf("Server close\n");
19 exit(0);
20 }
21 int main()
22 {
23 signal(SIGINT,sig_close);
24 init();
25 server();
26 return 0;
27 }

客户端

 1 //tcp_c.c
2 #include "header.h"
3 char name[30]; //name
4 int sockfd; //客户端socket
5 int mutax=0; //互斥变量
6 void init(){
7 printf("Client starts\n");
8 sockfd =socket(PF_INET,SOCK_STREAM,0);
9 struct sockaddr_in addr;
10 addr.sin_family =PF_INET;
11 addr.sin_port=htons(PORT);
12 addr.sin_addr.s_addr=inet_addr(IP);
13 if(connect(sockfd,(struct sockaddr*)&addr,sizeof (addr))==-1){
14 perror("connect failed\n");
15 exit(-1);
16 }
17 }

通信

 1 void start(){
2 pthread_t pid;
3 void* receive_thread(void*);
4 pthread_create(&pid,0,receive_thread,0);
5 while(1){
6 char buf[100]={};
7 gets(buf);
8 char msg[100]={};
9 if(mutax){
10 mutax=0;
11 continue;
12 }
13 sprintf(msg,"%s said:%s",name,buf);
14 send(sockfd,msg,strlen(msg),0);
15 }
16
17 }
18 void* receive_thread(void *p){
19 while(1){
20 char buf[100]={};
21 if(recv(sockfd,buf,sizeof(buf),0)<=0){
22 break;
23 }
24 printf("%s\n",buf);
25 }
26 }
27 void sig_close(){
28 close(sockfd);
29 exit(0);
30 }
31 int main(){
32 signal(SIGINT,sig_close);
33 printf("Please input your name:");
34 scanf("%s",name);
35 mutax=1;
36 init();
37 if(mutax)
38 send(sockfd,name,strlen(name),0);
39 start();
40 return 0;
41 }

基于Linux的TCP网络聊天室的更多相关文章

  1. 基于LINUX的多功能聊天室

    原文:基于LINUX的多功能聊天室 基于LINUX的多功能聊天室 其实这个项目在我电脑已经躺了多时,最初写完项目规划后,我就认认真真地去实现了它,后来拿着这个项目区参加了面试,同样面试官也拿这个项目来 ...

  2. Qt NetWork即时通讯网络聊天室(基于TCP)

    本文使用QT的网络模块来创建一个网络聊天室程序,主要包括以下功能: 1.基于TCP的可靠连接(QTcpServer.QTcpSocket) 2.一个服务器,多个客户端 3.服务器接收到某个客户端的请求 ...

  3. 网络编程TCP协议-聊天室

    网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...

  4. Linux下TCP网络编程与基于Windows下C#socket编程间通信

    一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使s ...

  5. php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室)

    php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室) 一.总结 1.ajax长轮询和websocket都可以时间网络聊天室 ...

  6. 基于EPOLL模型的局域网聊天室和Echo服务器

    一.EPOLL的优点 在Linux中,select/poll/epoll是I/O多路复用的三种方式,epoll是Linux系统上独有的高效率I/O多路复用方式,区别于select/poll.先说sel ...

  7. 基于 OpenResty 实现一个 WS 聊天室

    基于 OpenResty 实现一个 WS 聊天室 WebSocket WebSocket 协议分析 WebSocket 协议解决了浏览器和服务器之间的全双工通信问题.在WebSocket出现之前,浏览 ...

  8. Python3 网络通信 网络聊天室 文件传输

    Python3 网络通信 网络聊天室 文件传输 功能描述 该项目将实现一个文字和文件传输的客户端和服务器程序通信应用程序.它将传输和接收视频文件. 文本消息必须通过TCP与服务器通信,而客户端自己用U ...

  9. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

随机推荐

  1. 病毒木马查杀实战第016篇:U盘病毒之逆向分析

    比对脱壳前后的程序 我们这次所要研究的是经过上次的脱壳操作之后,所获取的无壳病毒样本.其实我们这里可以先进行一下对比,看看有壳与无壳的反汇编代码的区别.首先用IDA Pro载入原始病毒样本: 图1 可 ...

  2. Windows 10 系统进入测试模式命令

    首先需要开启测试模式,内容如下: @bcdedit -set loadoptions DDISABLE_INTEGRITY_CHECKS @bcdedit -set TESTSIGNING ON 取消 ...

  3. Windows Pe 第三章 PE头文件-EX-相关编程-2(RVA_FOA转换)

    RVA-FOA之间转换 1.首先PE头加载到内存之后是和文件头内容一样的,就算是偏移不同,一个是磁盘扇区大小(400H)另一个是内存页大小(1000H),但是因为两个都是开头位置,所以相同. 2.看下 ...

  4. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

  5. src/main/resorces applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  6. DevEco Device Tool 2.1 Beta1在Hi3861开发板上可视化分析的体验

    DevEco Device Tool迎来了2.1 Beta1,新版本有很多亮点.在上次"DevEco Device Tool 2.1 Beta1 的Hi3861在Windows平台的编译体验 ...

  7. mybatis新手快速搭建成功详细操作

    1.数据库建表 在数据库中新建一个名为mybatis的数据库,在mybatis数据库中新建一张 t_user 表,表中有3个字段,id,name,password,代码如下: 新建一个mybatis数 ...

  8. [bug] Maven修改pom文件后jdk版本回退

    参考 https://www.cnblogs.com/wxgblogs/p/6696229.html

  9. [bug] CDH 安装 Error : No matching Packages to list

    信息 分析 我的系统是CentOS 7,而 cm 安装包是配合 redhat 6 的,应该选择 redhat 7 目录下的包 参考 https://community.cloudera.com/t5/ ...

  10. 还可以使用 -c 参数来显示全部内容,并标出不同之处 diff -c test2.txt test1.txt

    二.实例 在test目录下存放了两个文本文件,test1.txt  test2.txt . 比较这两个文件的异同. diff  test1.txt   test2.txt     "5c5& ...