为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

基于UDP的P2P模式的聊天程序

2011-01-14 19页 doc 330KB 27阅读

用户头像

is_348269

暂无简介

举报
基于UDP的P2P模式的聊天程序程序设计报告封面_06new 基于UDP的P2P模式的聊天程序 课题内容和要求 使用UDP协议编写聊天软件,使得客户端之间可以自由地进行键盘聊天。 【程序的具体要求】 以图形界面运行, 提供聊天内容输入界面和收到的文字聊天内容。 允许客户选择不同的其他客户方(peer)进行聊天,假定已知对方的IP地址。 需求分析 本次试验需要使用UDP协议的P2P模式,所以在试验之前应该对其进行一定了解。 UDP 是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供...
基于UDP的P2P模式的聊天程序
程序设计封面_06new 基于UDP的P2P模式的聊天程序 课题内容和要求 使用UDP编写聊天软件,使得客户端之间可以自由地进行键盘聊天。 【程序的具体要求】 以图形界面运行, 提供聊天内容输入界面和收到的文字聊天内容。 允许客户选择不同的其他客户方(peer)进行聊天,假定已知对方的IP地址。 需求分析 本次试验需要使用UDP协议的P2P模式,所以在试验之前应该对其进行一定了解。 UDP 是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。UDP协议适用端口分别运行在同一台设备上的多个应用程序。UDP协议的全称是用户数据报协议,在网络中它与TCP协议一样用于处理UDP数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。 UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天,UDP仍然不失为一项非常实用和可行的网络传输层协议。与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据报的形式。一个典型的数据报就是一个二进制数据的传输单位。每一个数据报的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。 P2P是英文Peer-to-Peer(对等)的简称,又被称为“点对点”。“对等”技术,是一种网络新技术,依赖网络中参与者的计算能力和带宽,而不是把依赖都聚集在较少的几台服务器上。P2P还是英文Point to Point (点对点)的简称。它是下载术语,意思是在你自己下载的同时,自己的电脑还要继续做主机上传,这种下载方式,人越多速度越快但缺点是对硬盘损伤比较大(在写的同时还要读),还有对内存占用较多,影响整机速度。点对点技术(peer-to-peer, 简称P2P)又称对等互联网络技术,是一种网络新技术,依赖网络中参与者的计算能力和带宽,而不是把依赖都聚集在较少的几台服务器上。但P2P并非纯粹的点对点技术,实为解作群对群(Peer-to-Peer)。在虚拟私人网络VPN (Virtual Private Network)中,也有P2P这个名称,它才是真正解作点对(Point-to-Point)。对等联网:1、是只读的网络的终结(Peer-to-peer is the end of the read-only Web)。2、使你重新参与互联网(Peer-to-peer allows you to participate in the Internet again)3、使网络远离电视(Peer-to-peer steering the Internet away from TV)如上文所言,P2P不是一个新思想,从某些角度看它甚至是整个最初创建互联网的最基本的思想。 本次编程用的工具是VC6.0,因为需要做图形化界面,所以又自学了MFC。 这个试验的主要部分在,使用UDP协议上面,制作图形界面,创建套接字等方面。运行以后程序会出现很多的.h和.cpp的文件,和主代码写于在UDPChatDlg.cpp文件和UDPSock.cpp文件中。在做图形界面的时候,我打算做一个对话框,一个输入框,两个IP地址栏,两个端口栏,一个发送键,一个关闭键,一个设置IP地址键。每一个界面都对应一个类来实现其功能。 在UDPChatDlg.cpp中,BOOL CUDPChatDlg::OnInitDialog()中,实现了很多的功能,创建调用套接字、获得主机IP和端口号,以及对方的的IP初始值。void CUDPChatDlg::OnBtnConn()中,实现了设置键的功能。void CUDPChatDlg::OnBtnSend()中,是实现了发送的功能,读取输入框的信息并点击响应,使其能够显示在对话框,而且会对另外类的功能进行调用。void CUDPChatDlg::SendMsg()是自己添加的功能,使其图形化界面比较完善,可以显示发送方还有接收方。void CUDPChatDlg::OnBtnFont()也是添加的一项功能,用来调节字体大小颜色等。 在UDPSock.cpp中,void CUDPSock::OnReceive()这个需要说明,是为了接收信息的,其中调用了自己定义的结构,用于灵活分配空间,在试验过程中,在这个地方也出现了问题。 概要设计 这次试验程序的代码,我将程序的头文件和源文件分开些的。另外要说明的是,试验代码是用CSocket写的,CSocket是多线程的。 头文件中,Protocol.h文件是我自己写的代码,用于实现动态的获得消息,可以是程序在运行获得消息的时候,首先获得报头,然后再去获得消息的数据包,这样可以分配合适的内存,不要分配固定的内存。 UDPChat.h文件里面用到了CWinApp,MFC 中的主应用程序类封装用于 Windows 操作系统的应用程序的初始化、运行和终止。基于框架生成的应用程序必须有且仅有一个从 CWinApp 派生的类的对象。在创建窗口之前先构造该对象。 UDPChatDlg.h文件中,CUDPSock m_sockUDP;来使用UDP套接字,CHARFORMAT m_cfDefault;来控制默认字体,void SendMsg(BOOL bSelf, CString strName, CTime &time, CString strMsg, CHARFORMAT &cf);显示消息的函数。 在UDPSock.h中,主要是对CUDPSocket进行声明调用等。 源文件中,很多都是框架的代码,在此可以忽略。对一些功能函数和模块进行说明。 StdAfx.cpp文件中,用于调用程序所有的主要头文件,一定不能省略。 对于UDPChat.cpp文件,其实不用进行过多的说明,但是在程序中,一定要注意AfxInitRichEdit();初始化RichEdit,否则会出现一些问题。 接下来是UDPChatDlg.cpp源文件,这是程序的主要代码,很多的框架代码以及功能函数都在这个地方。1、BOOL CUDPChatDlg::OnInitDialog()中,CString str, strSockName, strPort;是为了获取主机IP。m_sockUDP.Close();是为了创建UDP套接字,在程序中,我对其进行了封装,然后调用。m_sockUDP.GetSockName(strSockName, uiPort);可以用来获取本机的端口,因为题目说在已知对方IP的条件下,所以当然要获得IP,虽然也可以手动查询本机IP,但是这样的话方便了很多。2、CUDPChatDlg::OnBtnConn()中,实现了设置键的功能,就是在输入对方IP和端口号以后,进行连接响应。3、void CUDPChatDlg::OnBtnSend()中,是进行主要工作,调用一些功能以及响应发送的命令。m_ctrlRichSend.SetFocus();是用于获取字符串,清空发送框。T_MSG_STRUCT tMsgHdr;用于发送数据包准备工作。lstrcpy(lpMsg, str.GetBuffer(0));str.ReleaseBuffer();用来复制消息内容。m_ctrlRichSend.GetDefaultCharFormat(tMsgHdr.cf); 用来设置字体。tMsgHdr.timeSent = CTime::GetCurrentTime();用于设置发送时间。tMsgHdr.uiMsgLen = str.GetLength();用于设置消息长度,_tcscpy(tMsgHdr.szName, m_strSelfName); 用于设置发送者名称,DWORD dwIPAddress; 等代码 用于获取目的主机的IP和端口。还有一些功能就不一一介绍了,在下面的程序都有给出注释。4、最后void CUDPChatDlg::OnBtnFont()中,是自己添加的功能,用于实现修改字体的大小,颜色,字体等功能。 最后是UDPSock.cpp源文件,void CUDPSock::OnReceive(int nErrorCode)是这个文件的主要部分,实现了先接收消息头部、然后接收消息,并显示别人发送过来的消息。其实在抓取消息的时候,我并没有用线程,而是像一个死循环一样,不断的抓取信息,知道用户点击发送才开始响应,并获取消息和显示。 详细设计 因为程序代码含有很多框架的代码,都是系统自带的,所以我找一些重要的自己写的代码附在此部分。 1、UDPChatDlg.cpp文件中的代码是主要代码,所以全部反映出来: #include "stdafx.h" #include "UDPChat.h" #include "UDPChatDlg.h" #include "Protocol.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CUDPChatDlg dialog CUDPChatDlg::CUDPChatDlg(CWnd* pParent /*=NULL*/) : CDialog(CUDPChatDlg::IDD, pParent) { //{{AFX_DATA_INIT(CUDPChatDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CUDPChatDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CUDPChatDlg) DDX_Control(pDX, IDC_RICHEDIT_BOX, m_ctrlRichBox); DDX_Control(pDX, IDC_RICHEDIT_SEND, m_ctrlRichSend); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CUDPChatDlg, CDialog) //{{AFX_MSG_MAP(CUDPChatDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_DESTROY() ON_BN_CLICKED(IDC_BTN_CONN, OnBtnConn) ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend) ON_BN_CLICKED(IDC_BTN_CLOSE, OnBtnClose) ON_BN_CLICKED(IDC_BTN_FONT, OnBtnFont) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CUDPChatDlg message handlers BOOL CUDPChatDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here ////////////////////////////////////////////////////////////////////////// WSADATA wsaData; TCHAR name[155]; TCHAR *ip; PHOSTENT hostinfo; // 获取本机IP地址 CString str, strSockName, strPort; UINT uiPort; if (WSAStartup(MAKEWORD(2, 0), &wsaData ) == 0) { if (gethostname(name, sizeof(name)) == 0) { if ((hostinfo = gethostbyname(name)) != NULL) { ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list); } } WSACleanup(); } str.Format(_T("%s"), ip); GetDlgItem(IDC_EDIT_ADDRESS_LOCAL)->SetWindowText(str); // 创建UDP套接字 m_sockUDP.Close(); if (!m_sockUDP.Create(0, SOCK_DGRAM, NULL)) { MessageBox(_T("连接服务器失败!"), _T("提示"), MB_OK | MB_ICONINFORMATION); return FALSE; } // 获取本机端口 m_sockUDP.GetSockName(strSockName, uiPort); strPort.Format(_T("%u"), uiPort); GetDlgItem(IDC_EDIT_LOCAL_PORT)->SetWindowText(strPort); // 初始化名字 m_strSelfName.Format(_T("<%s:%u>"), str, uiPort); // 初始值 ((CIPAddressCtrl *)GetDlgItem(IDC_IPADDRESS_REMOTE))->SetAddress(127, 0, 0, 1); GetDlgItem(IDC_EDIT_REMOTE_PORT)->SetWindowText(_T("0")); // 默认字体 ZeroMemory(&m_cfDefault, sizeof(CHARFORMAT)); m_cfDefault.yHeight = 180; m_cfDefault.cbSize = sizeof(CHARFORMAT); m_cfDefault.dwMask |= CFM_SIZE; m_cfDefault.dwMask |= CFM_FACE; m_cfDefault.dwMask |= CFM_BOLD; m_cfDefault.dwMask |= CFM_ITALIC; m_cfDefault.dwMask |= CFM_OFFSET; m_cfDefault.dwMask |= CFM_STRIKEOUT; m_cfDefault.dwMask |= CFM_UNDERLINE; m_cfDefault.dwEffects &= ~CFE_BOLD; m_cfDefault.dwEffects &= ~CFE_ITALIC; m_cfDefault.dwEffects &= ~CFE_STRIKEOUT; m_cfDefault.dwEffects &= ~CFE_UNDERLINE; m_cfDefault.yOffset = 0; lstrcpy(m_cfDefault.szFaceName, _T("宋体")); ////////////////////////////////////////////////////////////////////////// return TRUE; // return TRUE unless you set the focus to a control } void CUDPChatDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CUDPChatDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CUDPChatDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CUDPChatDlg::OnDestroy() { CDialog::OnDestroy(); // TODO: Add your message handler code here ////////////////////////////////////////////////////////////////////////// m_sockUDP.Close(); ////////////////////////////////////////////////////////////////////////// } void CUDPChatDlg::OnBtnConn() { // TODO: Add your control notification handler code here ////////////////////////////////////////////////////////////////////////// UpdateData(FALSE); MessageBox(_T("设置成功!"), _T("提示"), MB_OK | MB_ICONINFORMATION); ////////////////////////////////////////////////////////////////////////// } void CUDPChatDlg::OnBtnSend() { // TODO: Add your control notification handler code here ////////////////////////////////////////////////////////////////////////// CString str; INT iLen = m_ctrlRichSend.GetWindowTextLength(); // 条件验证 if (iLen == 0) { MessageBox(_T("发送内容不能为空,\n请重新输入!"), _T("提示"), MB_OK | MB_ICONINFORMATION); return; } if (iLen >= 1000) { MessageBox(_T("您所发的信息太长。"), _T("请截短信息"), MB_OK | MB_ICONINFORMATION); return; } // 获取字符串,清空发送框 m_ctrlRichSend.SetFocus(); m_ctrlRichSend.SetSel(0, iLen); str = m_ctrlRichSend.GetSelText(); m_ctrlRichSend.ReplaceSel(_T("")); // 发送数据包准备工作 T_MSG_STRUCT tMsgHdr; LPTSTR lpMsg = new TCHAR[str.GetLength() + 1]; // 复制消息内容 lstrcpy(lpMsg, str.GetBuffer(0)); str.ReleaseBuffer(); // 设置字体 m_ctrlRichSend.GetDefaultCharFormat(tMsgHdr.cf); // 设置发送时间 tMsgHdr.timeSent = CTime::GetCurrentTime(); // 设置消息长度 tMsgHdr.uiMsgLen = str.GetLength(); // 设置发送者名称 _tcscpy(tMsgHdr.szName, m_strSelfName); // 获取目的主机的IP和端口 DWORD dwIPAddress; ((CIPAddressCtrl *)GetDlgItem(IDC_IPADDRESS_REMOTE))->GetAddress(dwIPAddress); CString strPort; GetDlgItem(IDC_EDIT_REMOTE_PORT)->GetWindowText(strPort); // 设置SOCKADDR_IN SOCKADDR_IN clientaddr; clientaddr.sin_addr.S_un.S_addr = htonl(dwIPAddress); clientaddr.sin_family = AF_INET; clientaddr.sin_port = htons(atoi(strPort)); // 发送数据包 m_sockUDP.SendTo(&tMsgHdr, sizeof(T_PACKET_MSG), (SOCKADDR *)&clientaddr, sizeof(clientaddr)); m_sockUDP.SendTo(lpMsg, (str.GetLength() + 1) * sizeof(TCHAR), (SOCKADDR *)&clientaddr, sizeof(clientaddr)); // 目的主机的名称 CString strRemoteName; strRemoteName.Format(_T("<%s:%s>"), inet_ntoa(clientaddr.sin_addr), strPort); // 显示到聊天框中 SendMsg(TRUE, strRemoteName, tMsgHdr.timeSent, lpMsg, tMsgHdr.cf); // 焦点回到发送框 m_ctrlRichSend.SetFocus(); // 释放空间 SAFEDELETEA(lpMsg); ////////////////////////////////////////////////////////////////////////// } ////////////////////////////////////////////////////////////////////////// //************************************ // Method: SendMsg // FullName: CUDPChatDlg::SendMsg // Access: protected // Returns: void // Qualifier: // Parameter: BOOL bSelf 是否是自己发送的 // Parameter: CString strName 要显示的发送、目的主机的名字 // Parameter: CTime & time 发送时间 // Parameter: CString strMsg 消息内容 // Parameter: CHARFORMAT & cf 字体 //************************************ void CUDPChatDlg::SendMsg(BOOL bSelf, CString strName, CTime &time, CString strMsg, CHARFORMAT &cf) { CString str; m_ctrlRichBox.AddText(_T("\r\n"), m_cfDefault); str.Format(_T("[%s] %s %s 说:\r\n"), time.Format(_T("%H:%M:%S")), bSelf ? _T("你对") : strName, bSelf ? strName : _T("对你")); if (bSelf) { // 显示自己发送的标题 m_ctrlRichBox.AddTitle(str, m_cfDefault, RGB(0, 128, 64)); } else { // 显示别人发送的标题 m_ctrlRichBox.AddTitle(str, m_cfDefault); } str.Format(_T("%s"), strMsg); // 显示消息 m_ctrlRichBox.AddText(str, cf); // 任务栏按钮闪烁效果 if (!bSelf && GetForegroundWindow() != this) { FlashWindow(TRUE); } } ////////////////////////////////////////////////////////////////////////// void CUDPChatDlg::OnBtnClose() { // TODO: Add your control notification handler code here OnCancel(); } void CUDPChatDlg::OnBtnFont() { // TODO: Add your control notification handler code here ////////////////////////////////////////////////////////////////////////// CHARFORMAT cf; LOGFONT lf; memset(&cf, 0, sizeof(CHARFORMAT)); memset(&lf, 0, sizeof(LOGFONT)); m_ctrlRichSend.GetDefaultCharFormat(cf); //得到相关字体属 BOOL bIsBold = cf.dwEffects & CFE_BOLD; BOOL bIsItalic = cf.dwEffects & CFE_ITALIC; BOOL bIsUnderline = cf.dwEffects & CFE_UNDERLINE; BOOL bIsStrickout = cf.dwEffects & CFE_STRIKEOUT; //设置属性 lf.lfCharSet = cf.bCharSet; lf.lfHeight = cf.yHeight / 15; lf.lfPitchAndFamily = cf.bPitchAndFamily; lf.lfItalic = bIsItalic; lf.lfWeight = (bIsBold ? FW_BOLD : FW_NORMAL); lf.lfUnderline = bIsUnderline; lf.lfStrikeOut = bIsStrickout; lstrcpy(lf.lfFaceName, cf.szFaceName); CFontDialog dlg(&lf, CF_EFFECTS | CF_SCREENFONTS, NULL, this); dlg.m_cf.rgbColors = cf.crTextColor; if (dlg.DoModal() == IDOK) { dlg.GetCharFormat(cf);//获得所选字体的属性 m_ctrlRichSend.SetWordCharFormat(cf); m_ctrlRichSend.SetDefaultCharFormat(cf); } ////////////////////////////////////////////////////////////////////////// } BOOL CUDPChatDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class ////////////////////////////////////////////////////////////////////////// // 屏蔽ENTER和ESC if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) { return TRUE; } ////////////////////////////////////////////////////////////////////////// return CDialog::PreTranslateMessage(pMsg); } 2、UDPSock.cpp文件中的代码是自己编写用于接收信息的,所以把OnReceive()类附在这里。 void CUDPSock::OnReceive(int nErrorCode) { // TODO: Add your specialized code here and/or call the base class ////////////////////////////////////////////////////////////////////////// CString strRemoteName; UINT uiPort; T_PACKET_MSG tMsg; // 接收消息头部 ReceiveFrom(&tMsg.tMsgHdr, sizeof(T_MSG_STRUCT), strRemoteName, uiPort); LPTSTR lpMsg = new TCHAR[tMsg.tMsgHdr.uiMsgLen + 1]; // 接收消息 ReceiveFrom(lpMsg, (tMsg.tMsgHdr.uiMsgLen + 1) * sizeof(TCHAR), strRemoteName, uiPort); // 显示别人发送的消息 ((CUDPChatDlg *)AfxGetApp()->GetMainWnd())->SendMsg(FALSE, tMsg.tMsgHdr.szName, tMsg.tMsgHdr.timeSent, lpMsg, tMsg.tMsgHdr.cf); // 释放空间 SAFEDELETEA(lpMsg); ////////////////////////////////////////////////////////////////////////// CSocket::OnReceive(nErrorCode); } 3、UDPChatDlg.h和UDPSock.h的头文件中用来封装套接字、使用UDP协议还有一些声明。在此就不给出。 测试数据及其结果分析 程序的测试部分通过截图来表现,也会附上响应的文字说明。 图一 本图显示的是程序的一个功能,可以调节字体。 图二 图三 从以上两个截图可以看出,生成的端口号不同,本机的IP是一样的,所以完成的功能是,可以实现同一个主机进行对话,这样方便代码编写时候遇到问题对其进行相关的检测。 图四 图五 图六 以上三个截图可以发现,上面本机的IP地址并不一样,端口号也不一样,所以是同一个局域网的两台不同电脑进行会话,实现了题目要求的基于UDP的P2P模式的聊天软件,而且也可以进行中英文的输入。 调试过程中的问题的 本次试验遇到了很多问题,首先是CSocket的线程问题,在编写程序之前,并没有注意到CSocket是多线程的所以出现了一些问题。 另外,是自己粗心的问题,在编写程序过程中,运行了时候,总是没有在消息栏显示消息,最后通过检测发现自己忘记了添加接收消息的函数,以至于消息都没有接收,怎么会显示。所以添加了void CUDPSock::OnReceive(int nErrorCode)类来实现这个功能。 然后在试验中,也发现了一个有点神奇的东西,就是AfxInitRichEdit();初始化RichEdit,如果不加这个的话,程序会出现相关的问题,如果不对RichEdit控件初始化,无法显示很多东西。 另外一些小问题都是比较好解决的,所以就不在此列出了。 其实我也在考虑用TCP去做一个聊天软件,这个是面向连接的,可以说比UDP要复杂的多。因为用CSocket是多线程的,编写比较简单,但是我也在思考不用这个去写,虽然会稍微复杂一点,但是也不会在线程上出现问题。
/
本文档为【基于UDP的P2P模式的聊天程序】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索