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. 使用DirectX截屏

    网上有很多关于DirectX截屏的文章,但大都是屏幕截图,很少有窗口截图,本文则两者都涉及到,先讲如何截取整个屏幕,再讲如何截取某个窗口,其实二者的区别不大,只是某个参数的设置不同而已,最后我们还将扩 ...

  2. 关于 C/C++ 函数调用约定

    关于 C/C++ 函数调用约定,大多数时候并不会影响程序逻辑,但遇到跨语言编程时,了解一下还是有好处的. VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调 ...

  3. 手撸了一个starter,同事直夸我666~

    Spring Boot starter原理 Spring Boot 将常见的开发功能,分成了一个个的starter,这样我们开发功能的时候只需要引入对应的starter,而不需要去引入一堆依赖了!st ...

  4. 【翻译】WPF中的数据绑定表达式

    有很多文章讨论绑定的概念,并讲解如何使用StaticResources和DynamicResources绑定属性.这些概念使用WPF提供的数据绑定表达式.在本文中,让我们研究WPF提供的不同类型的数据 ...

  5. 一个或多个筛选器或者Listeners启动失败 的问题探索以及解决方案

    2020年10月9日更新 经过本人对SSM框架理解的加深和对IDEA工具使用的熟悉,现提出一种新的解决办法,以前的解决办法可能存在问题 1. 问题描述: 使用IDEA作为开发工具,使用Maven作为项 ...

  6. python-内置函数-compile,eval,exec

    #将字符串,编译成python代码 compile()#执行,有返回值,执行表达式并获取结果 eval()#执行python代码,无返回值,接收:代码或者字符串 exec() s = "pr ...

  7. 【转】docker打包python应用

    转自https://www.cnblogs.com/shenh/p/9518343.html 一.前言 容器使用沙箱机制,互相隔离,优势在于让各个部署在容器的里的应用互不影响,独立运行,提供更高的安全 ...

  8. Java枚举类、注解和反射

    本文主要介绍的是枚举类,注解和反射.还有一些基础知识:static,基本数据类型,运算符优先级放在文中,以便查阅复习. 其中牵扯到泛型的部分,可参考本人的另一篇博客:(Collection, List ...

  9. c++逆向分析----返回对象

    对象不使用默认析构函数 class Test { public: char cNum1; int iNum2; int* pInt; }; Test _ReturnObject() { Test st ...

  10. Java堆的理解

    堆的核心概述 所有的对象实例以及数组都应当在运行时分配在堆上 从实际实用角度看 --"几乎所有的对象实例都在堆中分配内存" 数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这 ...