网上聊天 实验报告.docx
- 文档编号:7780375
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:14
- 大小:48.37KB
网上聊天 实验报告.docx
《网上聊天 实验报告.docx》由会员分享,可在线阅读,更多相关《网上聊天 实验报告.docx(14页珍藏版)》请在冰豆网上搜索。
网上聊天实验报告
C/S网络聊天室程序----实验报告
信科03
(1)班楼欢庆I
聊天室程序的设计说明
1.实现思想
在Internet上的聊天室程序一般都是以服务器提供服务端连接响应,使用者通过客户端程序登录到服务器,就可以与登录在同一服务器上的用户交谈,这是一个面向连接的通信过程。
因此,程序要在TCP/IP环境下,实现服务器端和客户端两部分程序。
实现语言C++,开发环境VC/MFC。
2.功能模块总纲
2.1服务器端工作流程
服务器端通过socket()系统调用创建一个Socket数组后(即设定了接受连接客户的最大数目),与指定的本地端口绑定bind(),就可以在端口进行侦听listen()。
如果有客户端连接请求,则在数组中选择一个空Socket,将客户端地址赋给这个Socket。
然后登录成功的客户就可以在服务器上聊天了。
实现方式采用异步非阻塞机制。
2.2客户端工作流程
客户端程序相对简单,只需要建立一个Socket与服务器端连接,成功后通过这个Socket来发送和接收数据就可以了。
2.3C/S实现过程
服务器端:
<1>首先使用WSAStartup函数来初始化网络环境。
<2>调用socket(AF_INET,SOCK_STREAM,0)函数来创建一个套接字。
<3>调用bind函数将本地地址与刚建立的套接字关联起来。
<4>调用listen函数监听发向该套接字的连接请求。
<5>客户端的连接请求放在连接请求队列里,服务器调用accept函数从连接请求队列中取出第一个请求,创建一个为之服务的新的套接字,该套接字处理所有与该客户交互操作的信息。
而服务器进程的监听套接字这时继续处理来自其他客户的连接请求,直到因队列空而等待新的连接请求的到来。
<6>调用closesocket()关闭监听套接字,释放套接字资源。
<7>调用WSACleanup函数释放相应资源。
客户端:
<1>首先使用WSAStartup函数来初始化网络环境。
<2>调用socket(AF_INET,SOCK_STREAM,0)函数来创建一个套接字。
<3>调用connect函数连接远程服务器,以请求服务。
<4>服务器相应连接请求后,此时客户端进程开始与服务器的交互操作,直到请求结束 为止。
<5>调用closesocket()关闭监听套接字,释放套接字资源。
<6>调用WSACleanup函数释放相应资源。
3.流程图设计
4.模块设计/主要函数功能说明
Client:
使用MFC基于对话框的模式进行编写
用户登入模块:
主要功能:
进行服务器IP地址的输入。
进行通讯端口号的输入(默认5000)
昵称的输入(默认guest)
OnOK()实现各编辑框信息的保存(相应地用变量保存输入的信息)
OnCancel()撤销操作
用户聊天模块:
主要功能:
OnLogin()调用用户登入模块。
并进行服务器请求连接OnSocketConnect()
OnSocketConnect()函数:
进行Socket数据库版本的协商WSAStartup(),并确认服务器IP输入格式是否正确。
同时调用socket()创建套接字用于连接。
初始化服务器SOCKADDR_IN的各参数的值。
然后调用connect()进行正式的服务器连接。
然后使用异步WSAAsyncSelect()函数处理WM_SOCKET_READ消息(通过消息处理函数OnSocketRead())接收其他用户发到服务器的消息。
OnLogout()调用WSACleanup()和closesocket()关闭套接字和套接字库。
OnSocketSend()调用send()通过通信端口将消息发送给服务器(某种意义上讲,发送给其他用户)。
Server:
基于MFC单文档进行编写
主要功能:
OnServerOpen()函数:
WSAStartup()初始化套接字库及版本协商。
Gethostname()获取本地主机IP地址作为服务器IP。
调用socket()创建服务器套接字,同时初始化各参数。
然后进行bind()操作。
将服务器端进行绑定。
同时用WSAAsyncSelect()对请求连接的客户机消息WM_SERVER_ACCEPT(使用消息处理函数OnServerAccept())进行相应处理。
最后用liston()监听到达的客户端请求。
OnServerAccept()函数:
调用accept()进行对客户端请求的回应。
即分配一个新的m_aClientSocket,相应地为其异步处理消息通过WSAAsyncSelect()中对WM_CLIENT_READCLOSE消息的处理。
服务器发送消息到客户机通知连接建立。
OnClientReadClose()处理WM_CLIENT_READCLOSE消息。
FD_READ时调用OnClientRead()进行处理,FD_CLOSE时调用OnClientClose()时进行处理。
OnClientRead()调用recv()接收从客户端发送过来的消息,同时调用OnServerBroadcast()将这个信息广播到各个连接到该服务器的客户端。
OnClientClose()关闭退出用户的socket。
OnServerBroadcast()函数:
向连接在服务器上的所有客户广播消息。
使用了send()函数。
5.主要代码分析:
Server:
voidCServerView:
:
OnServerOpen()//服务器开启
{
WSADATAwsaData;
intiErrorCode;
charchLocalInfo[64];
if(WSAStartup(WINSOCK_VERSION,&wsaData))
{
MessageBeep(MB_ICONSTOP);
MessageBox("Winsockcouldnotbeinitialized!
",AfxGetAppName(),MB_OK|MB_ICONSTOP);
WSACleanup();
return;
}
else
WSACleanup();
if(gethostname(chLocalInfo,sizeof(chLocalInfo)))
{
ReportWinsockErr("\nCouldnotresolvelocalhost!
\nAreyouon-line?
\n");
return;
}
CStringcsWinsockID="\n==>>服务器已经开启,端口号:
";
csWinsockID+=itoa(m_pDoc->m_nServerPort,chLocalInfo,10);
csWinsockID+="\n";
csWinsockID+=wsaData.szDescription;
csWinsockID+="\n";
PrintString(csWinsockID);
m_pDoc->m_hServerSocket=socket(PF_INET,SOCK_STREAM,DEFAULT_PROTOCOL);
if(m_pDoc->m_hServerSocket==INVALID_SOCKET)
{
ReportWinsockErr("Couldnotcreateserversocket.");
return;
}
m_pDoc->m_sockServerAddr.sin_family=AF_INET;
m_pDoc->m_sockServerAddr.sin_addr.s_addr=INADDR_ANY;
m_pDoc->m_sockServerAddr.sin_port=htons(m_pDoc->m_nServerPort);
if(bind(m_pDoc->m_hServerSocket,(LPSOCKADDR)&m_pDoc->m_sockServerAddr,sizeof(m_pDoc->m_sockServerAddr))==SOCKET_ERROR)
{
ReportWinsockErr("Couldnotbindserversocket.");
return;
}
iErrorCode=WSAAsyncSelect(m_pDoc->m_hServerSocket,m_hWnd,WM_SERVER_ACCEPT,FD_ACCEPT);
if(iErrorCode==SOCKET_ERROR)
{
ReportWinsockErr("WSAAsyncSelectfailedonserversocket.");
return;
}
if(listen(m_pDoc->m_hServerSocket,QUEUE_SIZE)==SOCKET_ERROR)
{
ReportWinsockErr("Serversocketfailedtolisten.");
m_pParentMenu->EnableMenuItem(ID_SERVER_OPEN,MF_ENABLED);
return;
}
PrintString("==>>服务器套接字初始化完成--等待连接.\n\n");
m_bServerIsOpen=TRUE;
return;
}
LRESULTCServerView:
:
OnServerAccept(WPARAMwParam,LPARAMlParam)//处理服务器接收WM_SERVER_ACCEPT消息的函数
{
intiErrorCode;
intnLength=sizeof(SOCKADDR);
inti;
if(WSAGETSELECTERROR(lParam))
{
ReportWinsockErr("ErrordetectedonentryintoOnServerAccept.");
return0L;
}
if(WSAGETSELECTEVENT(lParam)==FD_ACCEPT)
{
for(i=0;(i =INVALID_SOCKET);i++); if(i==MAXClient)return0L; PrintString("==>>一个客户连接成功! \n"); m_aClientSocket[i]=accept(m_pDoc->m_hServerSocket,(LPSOCKADDR)&m_sockClientAddr,(LPINT)&nLength); if(m_aClientSocket[i]==INVALID_SOCKET) { ReportWinsockErr("Serversocketfailedtoacceptconnection."); return0L; } CStringcsDottedDecimal="一个客户进行了连接"; csDottedDecimal+=inet_ntoa(m_sockClientAddr.sin_addr); csDottedDecimal+="\n"; PrintString("==>>"+csDottedDecimal); WSAAsyncSelect(m_aClientSocket[i],m_hWnd,WM_CLIENT_READCLOSE,FD_READ|FD_CLOSE); CStringcsText="服务器连接成功"; LPSTRlpszResponse=csText.GetBuffer(1000); iErrorCode=send(m_aClientSocket[i],lpszResponse,lstrlen(lpszResponse),NO_FLAGS); if(iErrorCode==SOCKET_ERROR) ReportWinsockErr("Errorsendingresponsetoclient."); //else //PrintString("Responsesent! \n"); //OnClientClose(); } return0L; } LRESULTCServerView: : OnClientReadClose(WPARAMwParam,LPARAMlParam)//处理WM_CLIENT_READCLOSE消息函数 { switch(WSAGETSELECTEVENT(lParam)) { caseFD_READ: OnClientRead(wParam,lParam); break; caseFD_CLOSE: OnClientClose(wParam,lParam); break; } return0L; } LRESULTCServerView: : OnClientRead(WPARAMwParam,LPARAMlParam)//处理客户端发送过来的消息 { intiBytesRead; intiBufferLength; intiEnd; intiSpaceRemaining; charchIncomingDataBuffer[1024]; inti; for(i=0;(i =wParam);i++) { } if(i==MAXClient)return0L; iBufferLength=iSpaceRemaining=sizeof(chIncomingDataBuffer); iEnd=0; iSpaceRemaining-=iEnd; iBytesRead=recv(m_aClientSocket[i],(LPSTR)(chIncomingDataBuffer+iEnd),iSpaceRemaining,NO_FLAGS); iEnd+=iBytesRead; if(iBytesRead==SOCKET_ERROR) ReportWinsockErr("OnClientReadrecvreportedasocketerror."); chIncomingDataBuffer[iEnd]='\0'; if(lstrlen(chIncomingDataBuffer)! =0) { PrintString(chIncomingDataBuffer); OnServerBroadcast(chIncomingDataBuffer); } else ; //SinceWindowssendnotificationofFD_READandFD_CLOSE, //assumetheclienthasclosedtheconnectionifzerobytes //arereceived.Theprogramusesablockingsocket,whichmeansifthe //connectionwerestillopen,recv()wouldwaitfordata. //OnClientClose(); return(0L); } LRESULTCServerView: : OnClientClose(WPARAMwParam,LPARAMlParam)//处理客户端退出的消息 { intiErrorCode,i; if(WSAGETASYNCERROR(lParam)) ReportWinsockErr("ErrordetectedonentryintoOnClientClose"); for(i=0;(i =wParam);i++); iErrorCode=closesocket(m_aClientSocket[i]); m_aClientSocket[i]=INVALID_SOCKET; if(iErrorCode==SOCKET_ERROR) ReportWinsockErr("Errorclosingclientsocket! "); else PrintString("==>>客户端套接字成功关闭,等待下一个客户到达! \n\n"); return0L; } LRESULTCServerView: : OnServerBroadcast(characSendBuff[])//向各客户端广播的消息函数 { inti; for(i=0;i { if(m_aClientSocket[i]! =INVALID_SOCKET) intiErrorCode=send(m_aClientSocket[i],acSendBuff,lstrlen(acSendBuff),NO_FLAGS); } return0L; } Client: voidCClientDlg: : OnSocketConnect()//连接服务器的函数 { WSADATAwsaData; DWORDdwIPAddr; SOCKADDR_INsockAddr; if(WSAStartup(WINSOCK_VERSION,&wsaData)) { MessageBox("CouldnotloadWindowsSocketsDLL.",NULL,MB_OK); return; } if((dwIPAddr=inet_addr(m_csIP))==INADDR_NONE) { MessageBox("IP地址错误! \n请重新输入! ",NULL,MB_OK); return; } else { m_hSocket=socket(PF_INET,SOCK_STREAM,0); sockAddr.sin_family=AF_INET; sockAddr.sin_port=m_iPort; sockAddr.sin_addr.S_un.S_addr=dwIPAddr; intnConnect=connect(m_hSocket,(LPSOCKADDR)&sockAddr,sizeof(sockAddr)); if(nConnect) ReportWinsockErr("连接失败! ! "); else MessageBox("服务器连接成功! ! ",NULL,MB_OK); intiErrorCode=WSAAsyncSelect(m_hSocket,m_hWnd,WM_SOCKET_READ,FD_READ); if(iErrorCode==SOCKET_ERROR) MessageBox("WSAAsyncSelectfailedonsocket",NULL,MB_OK); m_csRead=""; GetDlgItem(IDC_LOGIN)->EnableWindow(FALSE); GetDlgItem(IDC_LOGOUT)->EnableWindow(TRUE); GetDlgItem(IDC_SEND)->EnableWindow(TRUE); GetDlgItem(IDC_EDIT_SEND)->EnableWindow(TRUE); UpdateData(FALSE); } } LRESULTCClientDlg: : OnSocketRead(WPARAMwParam,LPARAMlParam)//处理WM_SOCKET_READ消息的函数 { intiBytesRead; intiBufferLength; intiEnd; intiSpaceRemaining; charchIncomingDataBuffer[100]; iBufferLength=iSpaceRemaining=sizeof(chIncomingDataBuffer); iEnd=0; iSpaceRemaining-=iEnd; iBytesRead=recv(m_hSocket,(LPSTR)(chIncomingDataBuffer+iEnd),iSpaceRemaining,0); iEnd+=iBytesRead; if(iBytesRead==SOCKET_ERROR) ReportWinsockErr("OnClientReadrecvreportedasocketerror."); chIncomingDataBuffer[iEnd]='\0'; if(lstrlen(chIncomingDataBuffer)! =0) { m_csRead=m_csRead+"\r\n"+chIncomingDataBuffer; GetDlgItem(IDC_EDIT_READ)->SetWindowText((LPCSTR)m_csRead); CEdit*pEdit; pEdit=(CEdit*)GetDlgItem(IDC_EDIT_READ); inti=pEdit->GetLineCount(); pEdit->LineScroll(i,0); } else ; //SinceWindowssendnotificationofFD_READandFD_CLOSE, //assumetheclienthasclosedtheconnectionifzerobytes
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 网上聊天 实验报告 实验 报告