LINUX下网络即时聊天程序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于TCP协议的简易网络聊天程序
一、设计原理:
即时通信(IM)是指能够即时发送和接收互联网消息等的业务。自1998年面世以来,特别是近几年的迅速发展,即时通信的功能日益丰富,逐渐集成了电子邮件、博客、音乐、电视、游戏和搜索等多种功能。即时通信不再是一个单纯的聊天工具,它已经发展成集交流、资讯、娱乐、搜索、电子商务、办公协作和企业客户服务等为一体的综合化信息平台。本课题实现简单的及时通讯中的聊天服务。
问题定义:
本课题要解决的问题是提供用户自由向另外一个不同的用户发
消息的同时接收来自其他用户的消息。
2. 可行性研究:
要实现即时通讯的聊天模块,可以在LINUX下搭建服务器,在提供给用户客户端程序。客户端和服务器之间通过TCP协议实现在线聊天。
需求分析:
(1)为了实现即时通讯的聊天服务,聊天服务器必须能够同时接
入多个用户,所以要支持并发,允许同时在线客户端数量至少大于3个。(2)要求服务器能接收多个用户的接入请求同时处理已经建立连接的用户的操作。(3)接收用户发过来的信息。(3)正确转发信息到达正确的用户。(4)提供简单的用户操作指令比如显示实时在线的用户。
(5).来自不同用户的信息的转发的同步控制(6)。给每个用户一个唯一的ID。
4. 总体设计
首先我们应该在设计LINUX平台设计服务器并且C语言编程。在实现并行处理时可以使用多进程也可以使用多线程,多线程可以方便的实现不同连接间简易的通信,系统开销小所以这里选用它。在连接的协议选择上,因为传送数据量小,这里选择面向连接可靠传输的TCP协议,相比将套接字嵌入FILE留种,这里使用调用常用的tcp 的套接字API(send,recv)读写缓冲区实现连接的方法.
5.详细设计
客户端:首先用户提供服务器IP和端口,然后创建套接字并连接到服务器,连接成功给予操作界面。设计用户登陆接口函数,发送名字用于登陆处理。主进程挂载随时接收用户键盘输入,并调用SEND()函数处理发送和指令操作。创立一个线程用于挂载阻塞的recv();将收到的信息打印。
和端口,主进程监听和循环接IP服务器:服务器创建通用的服务器套接字绑定
受客户端接入请求。接入用户后创建线程传入套接字,并接收用户的登陆。登陆处理后讲该线程绑定一个用户ID,并创建一个线程用于挂载RECV();第一个线程处理要发给本连接绑定用户的转发服务。同时设计在线用户的更新和打印处理。使用互斥锁来解决写入的同步控制问题,在更改全局变量时候锁住,当转发完毕时,解锁。
6.编码和单元测试
编码见代码和流程图。测试没有截图,提列测试出现的部分问题:(1)段错误(核心已转储),原因:字符串处理函数字符串数组与字符串指针的调用问题。改进:数组统一换字符串指针,分配空间。(2)初始值设定不是常量,原因初始化在main()开始前执行。改进:结构体分配在主函数里分配空间。(3)当recv()从缓冲器COPY的数据产生粘包。原因:没有消息边界,解决:每次收发大小固定住。(4)连接关闭处理。解决:设置套接字收发的标志位获取退出原因,友好退出时套接字函数返回0。
二、运行方法说明、运行结果
运行方法:linux下编译服务器gcc server.c die.c -lpthread -o server.out
Linux下编译客户端gcc client.c die.c -lpthread -o client.out
服务器运行server.out <端口号/服务名称>
客户端运行client.out <服务器地址><端口号/服务名称>
服务器运行成功后有提示,客户端运行成功并登陆成功后有欢迎
界面。
用户可以输入LIST命令来获得在线用户列表。
用户可以输入CLOSE来退出程序。
运行结果:能达到设计要求,运行速度正常。
三、流程图
客户端流程图开始
创建、设置套接字
Connect();
创建、设置套接字
Nameland();
Pthread_creat();
执行threadmain()
接受键盘输定长数Recv(
打印信是否输close
yes
no
定长数Send()
Close(sock)
结束
服务器流程图
开始
创建、设置套接字
Bamd();
Listrren();
threadmain(); 执行Accept()
id 传入套接字和
While(1)
threadmain(); 执行id
线程指定
传入套接字创建clientsock
While(1)
用户名登陆处理Pthread_craet();
Recv()定长数据
id
线程指If(recv!=0
serversock)Clos
更新用户名列结
判断收到的Pthread_crreat();息根据不同容进行封While(1)
封装信息ID=id
If(ID==id)
Closclientsock)
更新用户列
Send(转发信
服务器
#include
#include
#include
#include
#include
#include
#include
#include
#include Practical.h
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; //定义一个静态锁char *rmessage;//当前受到来自客户端的源信息
int currentID=6;
char *clientlist[5];//用户组姓名
void *ThreadMain(void *arg); //挂send
void *ThreadMain2(void *arg);//挂阻塞rcvd
typedef struct ThreadArgs {
int clntSock; //线程要处理的连接
int nameID;//用户在用户组的位置
}threadMessage;
int main(int argc, char *argv[]) {
if (argc != 2) // Test for correct number of arguments
DieWithUserMessage(Parameter(s),
char *servPort = argv[1]; // First arg: local port
rmessage=(char *)malloc(120);
memset(rmessage,0,120);
int servSock = SetupTCPServerSocket(servPort);
if (servSock < 0)
DieWithUserMessage(SetupTCPServerSocket() failed, %unable to establish); for (;;) { // Run forever
int clntSock = AcceptTCPConnection(servSock);
threadMessage *threadArgs = (threadMessage *) malloc(
sizeof(threadMessage));
if (threadArgs == NULL)