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. POJ1456贪心(set或者并查集区间合并)

    题意:       给你n商品,每个商品有自己的价值还有保质期,一天最多只能卖出去一个商品,问最大收益是多少? 思路:       比较好想的贪心,思路是这样,每一次我们肯定拿价值最大的,至于在那天拿 ...

  2. 堆栈上的舞蹈之释放重引用(UAF) 漏洞原理实验分析

    0x01 前言 释放重引用的英文名名称是 Use After Free,也就是著名的 UAF 漏洞的全称.从字面意思可以看出 After Free 就是释放后的内存空间,Use 就是使用的意思,使用释 ...

  3. HackingLab基础关

    目录 1:Key在哪里? 2:再加密一次你就得到key啦~ 3:猜猜这是经过了多少次加密? 4:据说MD5加密很安全,真的是么? 5:种族歧视 6:HAHA浏览器 7:key究竟在哪里呢? 8:key ...

  4. Day009 二维数组

    多维数组 多维数组是数组的嵌套(数组的元素是数组,数组的数组元素的元素是数组...),比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组. 二维数组 int a[][]=new int ...

  5. java之泛型的使用

    在java中,普通的类和方法只能用具体的类型,这对代码的限制很大,代码的可重用性大大降低. 那么如何才能让同一个类和方法使用不同类型的对象呢?在接触泛型之前我们可能会想到通过类型转换的方法来实现. p ...

  6. Web端直传数据至OSS

    官方文档 最佳实践 小程序直传实践 支付宝小程序直传实践 微信小程序直传实践 Web端PostObject直传实践 Web端PostObject直传实践简介 JavaScript客户端签名直传 服务端 ...

  7. 你管这破玩意叫CPU?

    每次回家开灯时你有没有想过,用你按的开关实际上能打造出 复杂的 CPU来,只不过需要的数量可能比较多,也就几十亿个吧. 伟大的发明 过去200年人类最重要的发明是什么?蒸汽机?电灯?火箭?这些可能都不 ...

  8. SAP ABAP ALV 颜色设置(两个ALV函数例子) 列 行 单元格

    @[TOC](设置ALV颜色)# 前言淦! 要求花花绿绿的ALV ,那就淦他! 需要的参数和对应颜色放在最后.稍微改改就能用. 介绍两个常用的ALV函数实现1.REUSE_ALV_GRID_DISPL ...

  9. 15.Git

    1.Git介绍 1.1版本控制(理解) 无论是代码编写,还是文档编写,我们都会遇到对文档内容反复修改的情况 1.2开发中存在的问题(理解) 程序员小明负责的模块就要完成了,就在即将提交发布之前的一瞬间 ...

  10. CentOS6.7系统文本安装-2020

    CentOS6.7系统文本安装 [日期:2016-01-30] 来源:Linux社区  作者:endmoon [字体:大 中 小]   一.选择虚拟机软件 1)VMware Workstation   ...