网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx

上传人:b****6 文档编号:8404530 上传时间:2023-05-11 格式:DOCX 页数:43 大小:368.31KB
下载 相关 举报
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第1页
第1页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第2页
第2页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第3页
第3页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第4页
第4页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第5页
第5页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第6页
第6页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第7页
第7页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第8页
第8页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第9页
第9页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第10页
第10页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第11页
第11页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第12页
第12页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第13页
第13页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第14页
第14页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第15页
第15页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第16页
第16页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第17页
第17页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第18页
第18页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第19页
第19页 / 共43页
网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx_第20页
第20页 / 共43页
亲,该文档总共43页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx

《网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx(43页珍藏版)》请在冰点文库上搜索。

网络编程 基于TCP的简易聊天室 实验报告Word文件下载.docx

通行方面我在服务器接受客户端消息,和客户端接受服务器消息时使用了select模型,发送信息我使用的是普通的socket原语。

基本原理为服务器和客户端建立TCP连接,然后服务器负责路由消息到各个客户端。

4.优点和缺点

本软件对流程复杂的SELECT模型进行了细致的拆分和抽象,做到了逻辑流程清晰,每个函数简洁易懂,层次分明。

例如服务器启动函数:

它其实就完成了一个简单的流程,初始化socket,绑定,监听,初始化fd_socket集合,死循环调用select。

通过合理的封装底层原语和加入异常处理(异常交给顶层处理),使得代码专注于业务流程而不是繁杂的异常判断语句,在看下面这个函数DoSelect()。

它也只完成一个简单的流程,调用select,然后循环处理有读事件的socket。

接下来的DoFDRead()函数完成的事情也非常直接,如果有事件的socket是监听socket的话,那么就是接收到了一个新的连接,否则是接收到了新的小。

从上面这个简单的例子中可以看到,本软件最大的优点就是精心设计的类和函数。

避免了使用select模型常见的反复嵌套的循环和判断,每个函数清晰明了。

本系统还存在以下不足,首先是没有对界面做更深入的优化,只是做了最基本的调整,让输入输出更加雅观,其次是底层原语的封装并没有考虑到泛用性。

三、系统详细设计

这部分的文档在编码之前已经基本完成,由于时间较为仓促,部分内容可能和实际有所出入。

1.ChatServer类

该类负责完成服务器所有操作。

1)类图

2)成员变量

Map<

SOCKET,string>

m_clients聊天者的SOCKET和昵称的映射

fd_setm_fdSocket可用套接字集合

fd_setm_fdRead有事件发生的套接字集合

SOCKETm_sListen监听Socket

SOCKETm_sNowClient当前处理的客户套接字

intm_nPort监听端口

3)方法设计

voidBind()

voidListen()

voidSelect()

intRecv()

SOCKETAccept()

封装底层原语,并加入异常机制,使得外部调用简约明了。

构造函数

传入监听端口,初始化m_nPort

Start()

1)初始化监听套接字:

voidInitListenSocket()

2)绑定套接字至本地机器:

3)进入监听模式(设置为非阻塞):

4)初始化可用套接字集合voidInitFDSocket()

5)死循环,调用select方法DoSelect()

6)结束

DoSelect()

1)令m_fdRead=m_fdSocket

2)调用Select()

3)循环处理Select的结果DoFdRead(SocketsRead)

4)结束

DoFdRead(intiReadIndex)

1)判断是否为m_sListen

2)是m_sListenRecvNewConnect()

3)否则令m_sNowClient=m_fdRead[iReadIndex],调用RecvNewMessage()

RecvNewConnect()

1)判断是否达到套接字上线

2)调用Accept(),接收连接sClient

3)添加sCilent至m_fdSocket

4)添加套接字至m_clientsAddClientToInfoMap(stringname)

AddClientToInfoMap(stringname)

1)以SOKCET为键,name为值加入MAP

RecvNewMessage()

1)调用Recv函数

2)是否为命令IsCommand(stringstr)

3)是,则DoCommand(stringcmd)

4)否,则DoMessage(stringmsg)

5)结束

IsCommand(stringstr)

1)判断是否以"

/"

开头

DoCommand(stringcmd)

1)判断指令,并分析命令和参数(argc,argv)

2)调用指令处理函数

3)假设只有SetName命令,那么则将对应的套接字的名称设置

DoMessage(stringmsg)

1)拼接消息和名字BuildMsg(stringmsg)

2)在服务器上输出

3)消息路由DispatchMessage(stringmsg)

BuildMsg(stringmsg)

1)从m_clients中取出用户昵称

2)拼接字符串,形成格式如下

超人君(127.0.0.1)23:

49:

48说:

大家好!

即为:

昵称(IP地址)时间说:

消息正文

3)返回

DispatchMessage(stringmsg)

1)构造迭代器

2)遍历m_clients,若不是自身,则派送消息Send()

2.ChatClient类

该类负责处理客户端的所有操作。

 

2)字段设计

SOCKETm_sClient客户端自身的socket

SOCKETm_sServer服务器socket

stringm_name昵称

sockaddr_inm_ServerAddr;

服务器地址

根据端口号和服务器IP初始化m_server

Connect()

voidSend()

intSelect()

封装底层原语,加入异常处理,使得外部调用节约优雅。

voidStart()

1)初始化套接字InitClientSocket()

2)连接服务器Connect()设置为非阻塞模式

3)获取名字并发送至服务器InitName()

4)创建新线程并显示替他用户发言线程函数RecvMsgThread()

5)循环SendMsg()

6)关闭客户端CloseClient()

InitName()

1)提示输入昵称

2)获取昵称

3)合法性判断判断重复

4)添加命令格式

5)发送至服务器

SendMsg()

1)读取一行消息

2)判断是否为命令IsCommand(stringstr)

3)命令:

处理命令DoCommand(stringcmd)

4)消息:

处理消息DoMessage(stringmsg)

1)发送消息Send()

2)本地回显

RecvMsgThread()

1)初始化fdSocket,将m_sClient加入

2)创建fdRead

3)死循环,将m_sClient拷贝至fdRead

4)调用Select

5)循环,并输出收到的消息Recv()

3.SocketException类

该类负责记录SOKCET错误的代码以及错误信息。

4.命令协议

命令格式为/命令参数1参数2

1.退出:

/exit

2.获取在线用户列表:

/getuser

3.私聊:

/mUID信息

4.清屏:

/clear

5.帮助:

/help

处理方式

IsCommand(stringstr)负责分析是否为命令

判断首字母是否为斜杠"

str.at(0)=='

/'

ResoveCommand(stringcmd,int&

argc,stringargv[])若是命令将命令分析为argc,argv

DoCommand(stringcmd)处理命令,调用具体的XXX命令处理函数DoCmdXXXX()。

5.消息格式

1)公共消息

超人君(127.0.0.1)UID:

100说:

大家好!

李四(127.0.0.1)UID:

101说:

你好!

你悄悄地对ABCUID:

100说:

你好

CDFUID:

101悄悄地对你说:

3)服务器消息

【系统消息】XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。

4)程序内部提示

[SystemInfo]xxxxxxxxxxxxxxxxxxxxxxxxx

四、系统测试

1.服务器使用错误

2.客户端使用错误

3.启动服务器

5.启动客户端

客户端出现欢迎信息以及昵称输入提示。

服务器出现连接提示

6.关闭客户端

服务器出现断开连接提示

7.启动服务器错误提示

给出错误提示信息和提示代码

8.公开聊天

所有客户端以及服务器都会显示。

9.私聊

只有私聊的二人才能看到聊天信息,其他用户和服务器无法看到。

10.错误的私聊

私聊自己会得到一个错误提示

私聊不存在的用户也会得到一个错误提示

11.更名

12.获取在线用户

13.帮助

14.非法指令

非法指令会给出错误提示。

15.非法的指令参数

16.连接服务器失败

五、心得体会

这次实现我深入研究了select模型的使用,完成了一个简易的聊天室。

这次试验也使我在编程技巧方面也有了很大的提高。

六、完整代码

Charserverd.cpp服务器main函数文件

#include"

ChatServer.h"

SockException.h"

InitSock.h"

#include<

iostream>

usingnamespacestd;

InitSockinitSock;

intmain(intargc,char*argv[])

{

if(argc<

2)

{

cout<

<

"

Usage:

"

<

argv[0]<

Port"

endl;

return1;

}

ChatServercharServer(atoi(argv[1]));

try

charServer.Start();

catch(SockException&

e)

e.GetErrorInfo()<

[SystemError]ErrorCode:

e.GetErrorCode()<

}

ChatServer.h服务器类头文件

#ifndefCHAT_SERVER_H

#defineCHAT_SERVER_H

WinSock2.h>

string>

map>

ClientInfo.h"

classChatServer

public:

voidStart();

voidEnd();

ChatServer(intnPort);

~ChatServer(void);

private:

voidInitFDSocket();

voidDoSelect();

voidDoFDRead(SOCKETsRead);

voidRecvNewConnect();

stringIPAddrToString(sockaddr_insin);

voidAddClientToInfoMap(ClientInfoinfo);

voidRecvNewMessage();

boolIsCommand(stringstr);

voidDoCommand(stringcmd);

voidResoveCommand(stringcmd,int&

argc,stringargv[]);

voidDoCmdName(intargc,stringargv[]);

voidDoCmdGetUsers(intargc,stringargv[]);

voidDoMessage(stringmsg);

voidDoCmdPrivateMsg(intargc,stringargv[]);

stringBuildMessage(stringstr,boolbIsPublic);

stringBuildSystemMsg(stringstr);

voidDispatchMessage(stringmsg);

voidCloseConnect();

stringIntToString(intnNum);

//============简单封装底层原语=============

voidInitListenSocket();

voidBind();

voidListen();

intSelect();

intRecv(charmsgBuff[]);

voidSend(stringmsg,SOCKETclient);

SOCKETAccept(sockaddr_in&

sin);

//==========================================

map<

SOCKET,ClientInfo>

m_clients;

fd_setm_fdSocket;

fd_setm_fdRead;

SOCKETm_sListen;

SOCKETm_sNowClient;

intm_nPort;

};

#endifCHAT_SERVER_H

ChatServer.cpp服务器类

#pragmacomment(lib,"

ws2_32.lib"

#defineMAX_BUFF_SIZE500

typedefmap<

:

iteratormap_it;

ChatServer:

ChatServer(intnPort)

this->

m_nPort=nPort;

voidChatServer:

InitListenSocket();

Bind();

Listen();

InitFDSocket();

while(true)

DoSelect();

m_fdRead=m_fdSocket;

intnRet=Select();

if(nRet>

0)

for(inti=0;

i<

m_fdRead.fd_count;

i++)

{

DoFDRead(m_fdRead.fd_array[i]);

}

DoFDRead(SOCKETsRead)

if(sRead==m_sListen)

RecvNewConnect();

else

m_sNowClient=sRead;

RecvNewMessage();

if(m_fdSocket.fd_count>

=FD_SETSIZE)

[SystemInfo]接受连接达到上限,拒绝连接"

return;

sockaddr_inclientAddr;

m_sNowClient=Accept(clientAddr);

ClientInfoclientInfo(clientAddr);

cout<

[SystemInfo]接受来自"

clientInfo.GetIp()<

的连接"

FD_SET(m_sNowClient,&

m_fdSocket);

AddClientToInfoMap(clientInfo);

stringChatServer:

IPAddrToString(sockaddr_insin)

stringstr=inet_ntoa(sin.sin_addr);

str.append("

);

charszFormat[20];

str.append(ltoa(ntohs(sin.sin_port),szFormat,10));

returnstr;

AddClientToInfoMap(ClientInfoinfo)

m_clients[m_sNowClient]=info;

charmsgBuff[MAX_BUFF_SIZE];

intnRet=Recv(msgBuff);

stringmsg(msgBuff);

if(nRet<

=0)return;

if(IsCommand(msg))

DoCommand(msg);

DoMessage(msg);

intargc;

stringargv[100];

ResoveCommand(cmd,argc,argv);

if(argv[0]=="

name"

DoCmdName(argc,argv);

elseif(argv[0]=="

list"

DoCmdGetUsers(argc,argv);

elseif(argv[0]=="

m"

DoCmdPrivateMsg(argc,argv);

Send("

【系统消息】命令不存在,请使用/help命令查看命令帮助"

m_sNowClient);

argc,stringargv[])

intcount=0;

for(inti=1;

cmd.size();

charc=cmd.at(i);

if(c!

='

'

argv[count]+=c;

else

count++;

argc=++count;

DoCmdGetUsers(intargc,stringargv[])

if(argc!

=1)

stringmsg;

stringonline=IntToString(m_clients.size());

msg.append("

【系统消息】在线人数共"

+online+"

人:

msg.append("

\n\r"

map_itbegin=m_clients.begin();

map_itend=m_clients.end();

for(;

begin!

=end;

++begin)

msg.append("

\t"

+begin->

second.GetName()+"

second.GetIp());

UID:

+IntToString((int)begin->

first));

Send(msg,m_sNowClient);

DoCmdName(intargc,stringargv[])

=2)

【系统消息】命令格式错误USAGE:

/name你的昵称"

m_sNow

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2