p2p即时聊天系统

p2p即时聊天系统
p2p即时聊天系统

一、课程设计题目

基于P2P的局域网即时通信系统

二、实验环境及工具

1.计算机:PC机,PC虚拟机,

2.操作系统:Windows2000,WindowsXP

3.程序设计语言:VC 6.0

三、设计要求

1.实现一个图形用户界面局域网内的消息系统。

2.功能:建立一个局域网内的简单的P2P消息系统,程序既是服务器又是客户,服务器端口使用3333。

a)用户注册及对等方列表的获取:对等方A启动后,用户设置自己的

信息(用户名,所在组);扫描网段中在线的对等方(3333端口打

开),向所有在线对等方的服务端口发送消息,接收方接收到消息

后,把对等方A加入到自己的用户列表中,并发应答消息;对等方

A把回应消息的其它对等方加入用户列表。双方交换的消息格式自

己根据需要定义,至少包括用户名、IP地址。

b)发送消息和文件:用户在列表中选择用户,与用户建立TCP连接,

发送文件或消息。

3.用户界面:界面上包括对等方列表;消息显示列表;消息输入框;文件传输进程显示及操作按钮或菜单。

四、设计内容与步骤

1.学习Socket和TCP的基本原理和通信机制;

2.功能设计和界面设计

3.服务器功能的设计和实现

4.客户功能的设计和实现

5.课程设计任务说明书

五、方案设计

1.消息格式

本系统采用的消息格式是,文件头+消息内容

文件头为‘1’-‘9’,消息格式分配如下:

‘1’+本机名:登陆,发送给所有在线对等方的服务端口

‘2’+本机名:对登陆消息的回馈

‘3’+本机名:退出

‘4’+本机名:对话请求

“51”或”52”:对话请求的回应(是否同意)

‘6’+本机名+”退出对话”:退出对话

‘7’+对话内容:对话

‘8’+文件名长度+文件名+文件长度(转换成CString):请求传送

“91”同意传输

“92”拒绝

“93”磁盘已满

2.该软件分别开了3个监听端口:3333、3334、3335。之所以分开3个端口是因为各种传送的不同,在设计实验的过程中我发现对于登陆消息,

退出消息,应该用的socket是即用即断,即比如我收到登陆消息,并发

送回馈消息后就断开连接,这样就不用一个用户同时连接很多用户,如

果用完不断,就是全连接了。而文件传输应该跟对话传输分开,因此应

该再开一个端口。

3.在线用户的扫描:

本软件是通过扫描局域网内的在线用户(不一定打开软件),然后一一

发送登陆信息,如果收到登陆信息就在列表上增加用户并发送回馈,如

果收到回馈就在列表上增加用户,如果收到退出消息就删除用户。

4.文件传输

原本打算使用多线程文件传输,及发送端开多个线程同时读一个文件并

发送,接收端在磁盘开辟一个与接收文件大小一致的一个文件,然后接

收端开多个线程接收并各自负责写进特定文件位置,不过由于Socket匹

配问题,因此还是使用单线程传输比较简单一点。

六、方案实现及主要程序

1.工程中的类

(1).本软件中分别有三个CAsyncSocket的派生类,分别是C CtrlSocket,

CTalkSocket,CFileSocket

a)CCtrlSocket:用于接收及发送控制信息,包括文件头为‘1’(登陆);

‘2’(回馈);‘3’(退出);‘4’(对话请求);’5’(对话请求的回

应)的消息,对应监听端口是CTRLPORT——3333

b)CTalkSocket:用于接收及发送对话信息,及部分文件控制信息。包括

文件头为‘6’(退出对话);‘7’(对话);‘8’(请求传送);‘9’

(传送回应)的消息,对应监听端口是TALKPORT——3334

c)CFileSocket:用于发送及接收文件,对应监听端口是FILEPORT—

—3335

其它类如CPathDialog,CFileDlg与本设计的主要部分无紧要联系,故不一一说明了

2.类的具体实现

(1).CCtrlSocket类:主要部分有FD_READ及FD_CONNECT触发的事件,

OnConnect在建立连接后发送出相应的消息,而OnReceive在有消息到来的情况下处理消息

void CCtrlSocket::OnReceive(int nErrorCode)

{

// TODO: Add your specialized code here and/or call the base class char q[50];

char t;

unsigned int j;

CString tempaddr;

CString Ctemp;

UINT tempport;

this->Receive(q,strlen(q)+1,0);

t=q[0];

for(j=0;j

{

q[j]=q[j+1];

}

CChatApp *pApp=(CChatApp *) AfxGetApp();

CChatDlg *pDlg = (CChatDlg *) pApp->m_pMainWnd;

pDlg->UpdateData(true);

switch(t)//对控制信息的判断

{

case '1'://登陆

pDlg->m_listonline.InsertItem(0,q);

this->GetPeerName(tempaddr,tempport);

pDlg->m_listonline.SetItemText(0,1,tempaddr);

Ctemp="2"+pDlg->m_hostname;

this->Send(Ctemp,strlen(Ctemp)+1,0);

break;

case '2'://回馈

pDlg->m_listonline.InsertItem(0,q);

this->GetPeerName(tempaddr,tempport);

pDlg->m_listonline.SetItemText(0,1,tempaddr);

break;

case '3'://退出

for(j=0;jm_listonline.GetItemCount();j++)

{

if(pDlg->m_listonline.GetItemText(j,0)==q)

{

pDlg->m_listonline.DeleteItem(j);

}

}

break;

case '4'://请求对话

Ctemp.Format("%s",q);

Ctemp="是否接受"+Ctemp+"的对话请求?";

if(AfxMessageBox(Ctemp, MB_YESNO|MB_ICONQUESTION) != IDYES)

{

Ctemp="52";//拒绝

this->Send(Ctemp,strlen(Ctemp)+1,0);

break;

}

else

if(TalkSocket.m_hSocket!=INVALID_SOCKET)

{

Ctemp="6"+pDlg->m_hostname+"退出对话";//断开原来对话TalkSocket.Send(Ctemp,strlen(Ctemp)+1,0);

}

Ctemp="51";//同意

this->Send(Ctemp,strlen(Ctemp)+1,0);

this->GetPeerName(tempaddr,tempport);

pDlg->GetDlgItem(IDC_CUT_OFF)->EnableWindow(true);

pDlg->GetDlgItem(IDC_SEND_MSS)->EnableWindow(true);

pDlg->GetDlgItem(IDC_SEND_FILE)->EnableWindow(true);

_tcpSocketClose(TalkSocket);

_tcpSocketConnect(TalkSocket,tempaddr,TALKPORT);

pDlg->m_linkip=tempaddr;

pDlg->m_linkname.Format("%s",q);

break;

case '5'://请求对话的回应

if(q[0]=='1')

{

pDlg->m_editrec+="完成连接\r\n";

pDlg->GetDlgItem(IDC_CUT_OFF)->EnableWindow(true);

pDlg->GetDlgItem(IDC_SEND_MSS)->EnableWindow(true);

pDlg->GetDlgItem(IDC_SEND_FILE)->EnableWindow(true);

相关主题
相关文档
最新文档