《2022年网络程序设计报告 .pdf》由会员分享,可在线阅读,更多相关《2022年网络程序设计报告 .pdf(10页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Windows 网络程序设计报告-聊天工具的设计专业:通信 092姓名:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 10 页 - - - - - - - - - 一、设计需求在网络越来越发达的今天, 人们对网络的依赖越来越多, 越来越离不开网络,大家所熟知的腾讯QQ、微软的 MSN、移动的 Fetion 等,都是做的比较成功的实时聊天工具。 随着网络的日益普及, 各种聊天工具也层出不穷, 但当我们学习了Windows 网络程序设计这门课程之后,我们便会觉得,其实要实现
2、简单的网络通讯其实并不难。 接下来的课程设计就是针对一个简单的网络聊天程序,利用 C+为开发工具,实现基本的通讯功能。二、实现功能(1)登录功能。(2)客户可以通过服务器转发,实现一对一和多对多聊天。(3)实现呼叫功能。(4)客户端程序应该可以实时显示目前其它用户的状态。(5)应该具有易用、美观的图形界面。三、功能分析(1)多人会话。 此程序分为服务器端和客户端,当客户端要进入聊天室的时候,就必须通过网络连接到服务端, 以实现和其它客户端的通讯功能。其中最简单的一种通讯方式就是多人会话, 运用多线程同时对多个用户的信息进行监听,服务器通过转发消息,让所有人都可以得到消息,实现多人会话。(2)一
3、对一会话。此程序的服务器端除了能够提供多人会话的功能外,还提供了私人聊天功能, 可以实现一对一的聊天。 就是在消息转发的时候, 私聊的消息只发给私聊的对象,而其他人看不到此消息,但是此消息会通过服务器端转发,然后再到达目的客户端。(3)服务器登陆。服务器端开启之后处于监听状态,多线程工作,接受每一个用户的连接请求。而客户端只需输入服务器端的IP 地址即可,端口在服务器端自动生成。(4)使用 Socket编程实现聊天工具客户端和服务端的设计。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - -
4、第 2 页,共 10 页 - - - - - - - - - 四、设计方案整 个 程 序 设 计 为 两 个 部 分 : 服 务 器(ChatRoomServer)和 客 户 端(ChatRoom),该程序分输入IP 地址和端口号后,能够连接到服务器,然后进行多人聊天。文件包括课程设计报告和程序代码。多人聊天的关键在于要将每个客户端发送过来的消息分发给所有其他客户端,为了解决这个问题, 在服务器程序中建立一个套接口链表,用来保存所有与客户端建立了连接的服务端口。下面描述了多人聊天的实现原理:当客户端 Client N 向对应的服务端口N 发送了消息 Message ,服务端口 N将 Messa
5、ge复制给所有套接口列表 (USERLIST)中的套接口缓冲区,然后向每个服务端口发送 WRITE 消息,使每个服务端口将Message发送给对应的客户端。这样,所有客户端就都获得了Message消息,实现了多人聊天功能。BOOL CClientSocketList:Sends(char *buff,int n) CClientSocket *curr=Head; while (curr) curr-Send(buff,n); curr=curr-Next; return true; USERLIST 表时多人聊天程序的核心, 它是一个动态变化的链表, 为空表示没有客户端建立了连接, 不为空时
6、每个元素就代表有一个客户端与服务器建立了连接。(一)客户端的设计 1. 首先利用对话框建立聊天程序的界面,以下是客户端的界面:最上面是一个接受数据的编辑框,下面分别是一个Ip 地址控件和发送数据的编辑框,左下角是触发发送数据的按钮。2. 加载套接字库,在 MFC 中用 AfxSocketInit()加载套接字库。需要注意的是这个函数要在程序的初始化函数中调用,即在 Appliacation的 InitInstance()中调用 AfxSocketInit(); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - -
7、 - - - - - 第 3 页,共 10 页 - - - - - - - - - 3. 初始化套接字。在对话框中添加一个成员函数SockInit(),用来初始化套接字,然后在对话框初始化函数OnInitDlg()中调用 SockInit()。Tip :因为聊天程序既包含接收端又包含发送端,所以需要绑定Ip 和端口。4. 创建多线程。接受数据时,如没有数据到来,则会阻塞,导致程序暂停运行,所以把接受数据工作放到单独的线程中。在OnInitDlg()中创建多线程。 Tip :因为需要给线程传递一个通信的套接字和响应消息的窗口句柄,所以需要额外定义一个结构体,用来存储这两个参数。struct RE
8、CVPARAM HWND hWnd; /接收数据窗体的句柄 SOCKET sock; /接收数据的套接字; 5. 实现线程过程函数。 Tip :如果要求不能用全局函数的话,那线程过程函数就要定义为 static(它属于类本身) . 在线程过程函数中循环接受消息,利用:PostMessgae ()函数给接受数据编辑框发送消息,以实现显示信息的功能6. 自定义消息的实现。 因为在 PostMessage中是自定义的消息 (WM_RECVDATA),所以需要完成消息映射。(1)定义消息值 #define WM_RECVDATA WM_USER+1 (2)声明消息处理函数: afx_msg void
9、OnRecvData(WPARAM wParam,LPARAM lParam);(3)完成消息映射: ON_MESSAGE(WM_RECVDATA,OnRecvData) 7. 实现 OnRecvData()函数。显示接收到的信息8. 实现 OnButtonSend() 函数。发送消息编写一个基于 MFC对话框的聊天程序:1.新建一个基于 MFC项目工程 Chat 2.加载套接字库,有下面两种方法,在这里选择第二种方法,因为更方便。方法一、使用 WSAStartup() 加载套接字库参考 MSDN中的范例代码 ,拷贝到自己的程序中修改即可。* 注意不再使用套接字后调用WSACleanup()
10、。WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 2, 2 );err = WSAStartup( wVersionRequested, &wsaData );if ( err != 0 ) return;if ( LOBYTE( wsaData.wVersion ) != 2 |HIBYTE( wsaData.wVersion ) != 2 ) WSACleanup( );return; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - -
11、 - - - 名师精心整理 - - - - - - - 第 4 页,共 10 页 - - - - - - - - - 方法二、使用 AfxSocketInit()加载套接字库( MFC)BOOL AfxSocketInit( WSADATA* lpwsaData = NULL ); 参数 1:指向 WSADATA 结构体的指针。WSAData机构体如下功能是 :存放 windows socket初始化信息 . struct WSAData WORD wVersion; WORD wHighVersion; char szDescriptionWSADESCRIPTION_LEN+1; char
12、 szSystemStatusWSASYSSTATUS_LEN+1; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; ; wVersion 为你将使用的 Winsock版本号,wHighVersion为载入的 Winsock动态库支持的最高版本,注意,它们的高字节代表次版本,低字节代表主版本。szDescription与 szSystemStatus由特定版本的 Winsock设置,实际上没有太大用处。iMaxSockets表示最大数量的并发Sockets ,其值依赖于可使用的硬件资源
13、。iMaxUdpDg表示数据报的最大长度 ;然而,获取数据报的最大长度,你需要使用WSAEnumProtocols对协议进行查询。最大数量的并发 Sockets并不是什么神奇的数字 ,它是由可用的物理资源来决定的. lpVendorInfo 是为 Winsock实现而保留的制造商信息 ,这个在 Windows 平台上并没有什么用处 .函数内部帮我们调用WSAStartup()加载 1.1 版本的套接字库。并且可以确保在应用程序终止之前调用WSACleanup() 终止套接字库的使用。这个函数在 CWinApp:InitInstance()中调用该函数。* 调用该函数需要包含头文件:Afxsoc
14、k.h 在这个程序中我们将这个头文件放在stdafx.h stdafx.h 是一个预编译头文件, 在这个头文件中包含了MFC运行必要的头文件和标准组件注意 Return Value所以设置一个 IF 语句判断字节库是否加载成功名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 10 页 - - - - - - - - - 3.初始化套接字,在 CChatDlg类中添加成员变量SOCKET m_socket; 添加成员函数 BOOL InitSocket();BOOL CCha
15、tDlg:InitSocket()m_socket=socket(AF_INET,SOCK_DGRAM,0);if(INVALID_SOCKET=m_socket)MessageBox( 套接字创建失败! );return FALSE;SOCKADDR_IN addrSock;addrSock.sin_family=AF_INET;addrSock.sin_port=htons(6000);addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/INADDR_ANY表示接受任意地址int retval; / 用来接受 bind 返回值retval=bi
16、nd(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR);if(SOCKET_ERROR=retval)closesocket(m_socket);MessageBox( 绑定失败 );return FALSE;之后在 BOOL CChatDlg:OnInitDialog() 中调用 BOOL CChatDlg:InitSocket() ,这样初始化的工作才算完成。4. 编写接收端程序:建立一个单独的线程用来接收数据,向这个线程传递两个参数: 套接字和对话框句柄。但是 CreateThread只能传递一个指针参数, 于是我们可以定义一个结构体包含套接字
17、和对话框句柄,然后将这样一个结构体的对象指针作为参数传递。结构体名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 10 页 - - - - - - - - - 以定义如下:struct RECVPARAM SOCKET sock; HWND hwnd; ;接下来创建线程函数,:* 一般来说,线程函数RecvProc应该是一个全局函数,而不能是一个对象的成员函数,否则会出错。因为要调用类的成员函数,必须先产生一个对象;而在创建线程时, 不能去创建或者传递一个对象, 所以不能直
18、接调用一个对象的成员函数作为线程入口函数。但是如果将它设置成为静态函数,那么它不属于任何具体的对象,这时可以将它作为线程入口函数。RECVPARAM *pRecvParam=new RECVPARAM;/用来传递参数的结构体pRecvParam-sock=m_socket;pRecvParam-hwnd=m_hWnd; / 所有与窗口有关的类都有一个数据成员m_hWnd,它保存了和这个类相关的窗口句柄Handle hThread=CreateThread(NULL,0,RecvProc/*线程函数 */,(LPVOID)pRecvParam,0,NULL);CloseHandle(hThrea
19、d);DWORD WINAPI CChatDlg:RecvProc(LPVOID lpParameter)SOCKET sock=(RECVPARAM*)lpParameter)-sock;HWND hwnd=(RECVPARAM*)lpParameter)-hwnd;SOCKADDR_IN addrFrom;int len=sizeof(SOCKADDR);char recvBuf200;char tempBuf300;int retval;while(TRUE)retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);if(
20、SOCKET_ERROR=retval)break;sprintf(tempBuf,%s 说:%s,inet_ntoa(addrFrom.sin_addr),recvBuf);:PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);/ 通过发送消息方式把数据传给对话框/ 传递一个自定义消息WM_RECVDATA/ 将数据通过 lParam进行传递return 0;实现消息响应函数步骤:定义消息 WM_RECVDATA :名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - -
21、 - - - - - 第 7 页,共 10 页 - - - - - - - - - #define WM_RECVDATA WM_USER+1 做一个消息相应函数原形的声明:afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam); 定义消息映射 ,注意不要写错位置:ON_MESSAGE(WM_RECVDATA,OnRecvData) 实现消息响应函数:void CChatDlg:OnRecvData(WPARAM wParam,LPARAM lParam) CString str=(char*)lParam; CString strTemp;
22、GetDlgItemText(IDC_EDIT_RECV,strTemp); str+=rn; str+=strTemp; SetDlgItemText(IDC_EDIT_RECV,str); 5.编写发送端程序最后为按钮添加消息实现代码:注:为使文本框支持多行,在属性里选中Multiline 。如果我们要在输入结束后以回车发送数据,只需把发送按钮的default button 按钮选中即可void CChatDlg:OnBtnSend() /1. 首先要得到 IP地址DWORD dwIP;(CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1)-GetAddre
23、ss(dwIP);/2. 定义地址结构体变量GetDlgItem(IDC_IPADDRESS1)得到的是 CWnd 指针/ 因为 GetAddress这个函数是 CIPAddressCtr 这个类的 所以要转换下SOCKADDR_IN addrTo;addrTo.sin_family=AF_INET;addrTo.sin_port=htons(6000);addrTo.sin_addr.S_un.S_addr=htonl(dwIP);/3. 得到发送编辑窗口要发送的数据CString strSend;GetDlgItemText(IDC_EDIT2_SEND,strSend);/4. 发送数据
24、sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR);SetDlgItemText(IDC_EDIT2_SEND,); (二)以下是服务端的设计,由于设计思路相同,只做简单分析1.首先利用对话框建立聊天程序的服务端界面名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 10 页 - - - - - - - - - 最上面是一个接受数据的编辑框,下面分别是一个Ip
25、地址控件和发送数据的编辑框,左下角是触发发送数据的按钮。2.加载套接字库,在MFC 中用 AfxSocketInit() 加载套接字库。需要注意的是这个函数要在程序的初始化函数中调用,即在 Appliacation 的 InitInstance() 中调用AfxSocketInit(); 3.初始化套接字。在对话框中添加一个成员函数SockInit() ,用来初始化套接字,然后在对话框初始化函数OnInitDlg() 中调用 SockInit() 。Tip:因为聊天程序既包含接收端又包含发送端,所以需要绑定Ip 和端口。4.创建多线程。接受数据时,如没有数据到来,则会阻塞,导致程序暂停运行,所
26、以把接受数据工作放到单独的线程中。在OnInitDlg() 中创建多线程。 Tip:因为需要给线程传递一个通信的套接字和响应消息的窗口句柄,所以需要额外定义一个结构体,用来存储这两个参数。struct RECVPARAM HWND hWnd; /接收数据窗体的句柄SOCKET sock; / 接收数据的套接字;5.实现线程过程函数。 Tip:如果要求不能用全局函数的话,那线程过程函数就要定义为 static(它属于类本身) .在线程过程函数中循环接受消息,利用:PostMessgae ()函数给接受数据编辑框发送消息,以实现显示信息的功能6.自定义消息的实现。因为在PostMessage 中是
27、自定义的消息(WM_RECVDATA ),所以需要完成消息映射。(1)定义消息值 #define WM_RECVDATA WM_USER+1 (2)声明消息处理函数: afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam); (3)完成消息映射: ON_MESSAGE(WM_RECVDATA,OnRecvData)7.实现 OnRecvData() 函数。显示接收到的信息8.实现 OnButtonSend() 函数。发送消息名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心
28、整理 - - - - - - - 第 9 页,共 10 页 - - - - - - - - - 程序流程图五结果及分析:此程序的功能达到了之前预想的可能,通过服务器端的消息转发,实现多用户之间的群聊, 和单个用户之间的私聊,完成了一个简单的网络聊天软件的功能。本次的实验,让我对于 CSocket 网络聊天类的使用有了更深入的了解,在关于网络编程的方面也有新的认识。虽然此程序的功能还比较的简单,而且某些方面还没能完善,但是,我相信我只是一个开始。开启登陆等待客户登陆客户端用户创建子套接字Message ChatServer ChatClient Message 登陆成功连接发送 message 显示找到客户端并显示登陆失败发送ID 和名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 10 页 - - - - - - - - -