




免费预览已结束,剩余8页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
摘要基本的网络编程都是建立在Winsock基础上的,作为网络编程接口,Winsock屏蔽了网络底层的复杂的协议和数据结构,因此,在Win32平台上,访问众多的基层网络协议,Winsock是首选接口。用Winsock构建一个网络聊天室,有两种基本的方式:数据报方式和流方式,即面向无连接的数据报方式和面向连接的流方式,对应的协议分别为UDP(User Datagram Protocol)协议和TCP(Transport Control Protocol)协议。本次我们设计的网络聊天室是基于UDP协议的无连接方式,软件编程则主要使用Winsock提供的API函数。关键字:网络编程 UDP协议 API函数1 设计目的与功能要求1.1 设计目的(1)编写一个简单的C/S模式的网络聊天室软件(2)进一步掌握利用Visual C+进行程序设计的能力;(3)进一步理解和运用面向对象程序设计的思想和方法;(4)初步掌握开发一个小型实用系统的基本方法;(5)理解Windows程序的运行过程。1.2 网络聊天室功能要求网络聊天室系统设计完成后,我们可以在一台计算机上运行服务端程序,然后在另一网络的其他计算机上运行客户端程序,登录到服务器上,各个客户之间就可以聊天,或者直接在一台计算机上同时运行服务器端和客户端,然后两者之间进行通信。1.2.1 服务器端功能要求(1)初始化socket, 创建服务器端。(2)维护一个链表,保存所有用户的IP地址、端口信息。(3)接受用户传送来的聊天信息,然后向链表中的所用用户转发。(4)接受用户传送来的连接判断命令,并向用户发出响应命令。1.2.2 客户端功能要求客户端界面上的两个文本框,一个用于显示接受的聊天信息,一个用来接受用户输入的聊天信息。当按下“发送”按钮时将信息发送给服务器。2 设计原理本次设计的题目是实现一个简单的C/S模式的网络聊天室,基于UDP协议,是不可靠的面向无连接的方式。设计的基本原理也就是UDP编程原理。UDP协议是一个简单的面向数据报的传输层协议,又叫用户数据报协议。它提供了无连接的、不可靠的数据传输服务。无连接是指它不像TCP协议那样在通信前先于对方建立连接以确定对方的状态。不可靠是指它直接安装指定的IP地址和端口号将数据包发送出去,如果对方不在线的话数据就可能丢失。UDP协议编程原理如下:2.1 服务器端原理(1)创建套节字(socket);(2)绑定IP地址和端口(bind);(3)收发数据(sendto/recvfrom);(4)关闭连接(closesocket)。2.2 客户端原理(1)创建套节字(socket);(2)收发数据(sendto/recvfrom);(3)关闭连接(closesocket)。UDP协议用于发送和接收数据的函数是sendto和recvfrom。它们的原形如下:int sendto( SOCKET s, /用于发送数据的套节字 Const char FAR *buf, /指向发送数据的缓冲区 int len, /要发送数据的长度 int flags, /一般指定为0/指向一个包含目标地址和端口号的sockaddr_in 结构 const struct sockaddr * to, int tolen); /为socket_ in 的结构大小同样UDP协议接收数据也需要知道通信对端的地址信息。int recvfrom(SOCKET s,char FAR * buf,int len,int flags,struct sockaddr FAR * from,int FAR* fromlen);2.3 网络聊天室设计流程该程序设计使用Windows Sockets编程。在数据传输协议中,我们使用UDP协议,UDP协议是无连接的协议,在服务器端不调用listen函数进行监听,也不调用accept函数建立连接, 其操作流程图如下图3-2所示:首先,用socket函数建立套接字,然后根据本地的IP进行绑定,然后就可以通过使用send 函数和 reve 函数来进行数据的发送和接收了。利用C语言编写Windows应用程序有两种方式:一种是Windows C编程方式,另一种是Visual C+编程方式。在一般情况下,Visual C+编程方式编写的程序源代码量小、开发时的工作量小、工作难度也较小,但编译后的代码量较大,运行速度略低;而Windows C编程方式编写的程序源代码量虽然较大,但可执行代码效率高。随着技术的进步,Visual C+编程方式已被广泛采用,但象网络编程等一些对速度要求高、对硬件操作较多的程序,大多数还是用Windows C编程方式开发的。另外,学习Windows C程序设计,还有助于更深入地了解Windows的内幕和Windows API。3 实现过程设计数据报方式又称无连接方式,对应的是UDP(User Datagram Protocol)协议。这种方式不提供数据无错保证,数据可能丢失或重复并且接收顺序混乱,后发出的报文可能会先收到,并且报文的长度是有限制的;不过,由于取消了重发校验机制,能够达到较高的通信速率,可以用于对数据可靠性要求不高的通信,如实时的语音、图像传送和广播消息等。和C语言一样,函数是Windows C编程的最基本的单位。不过,Windows C主要使用API函数,而网络编程则主要使用Winsock提供的API函数。因此,在该网络聊天室的设计中,我们将采用Winsock编程,而Winsock编程的一般过程是比较固定的。3.1 服务器端程序设计3.1.1 Winsock库德装入、初始化和释放所以的Winsock函数都是从WS2_32.DLL库导出的,VC+在默认的情况下并没有连接到该库,如果想使用Winsock API,就必须包含相应的库文件。#pragma comment(lib,“wsock32.lib”)每一个使用winsock的应用程序,都必须进行WSAStart函数调用,并且只有在调用成功之后才能使用其它的winsock网络操作函数。WSAstartup必须是应用程序首先调用的Winsock函数。它允许应用程序指定所需的Windows Sockets API 的版本,获取特定Winsock实现的详细信息。仅当这个函数成功执行之后,应用程序才能调用其他的Winsock API 函数。WSAStartup()函数原形为:int WSAStartup(/应用程序支持的最高Winsock库版本,高字节为此版本号,低字节为主版本号WORD wVresionRequested/一个指向WSADATA结构的指针,它用来返回DLL库德详细信息。LPWSADATA lpWSAData);每一个对WSAStartup的调用必须对应一个对WSAClearnup的调用,这个函数释放Winsock库。 int WSAClearnup(void);该过程的核心程序代码如下:WORD VersionRequested = MAKEWORD(1,1);WSADATA wsaData;WSAStartup(VersionRequested, &wsaData);/ 启动winsock服务if ( wsaData.wVersion != VersionRequested ) MessageBox(NULL,First Failed!,Error,0);WSACleanup();3.1.2 套节字的创建和关闭Winsock网络通信的第一步通常就是调用socket()函数。所有的通信在建立之前都有要创建一个Socket。该函数的功能与文件操作中的fopen()类似,返回值是由Winsock定义的一种数据类型SOCKET,它实际是一个整型数据,是Socket创建成功时,Windows分配给程序的Socket编号,后面调用传输函数时,可以把它像文件指针样引用。使用套节字之前,必须调用socket函数创建一个套节字对象,此函数调用成功将返回套节字的句柄。Socket()函数的原形如下:SOCKET socket( int af,/用来指定套节字使用的地址格式,WinSock中只支持AF_INET int type, /用来指定套节字的类型/配合type参数使用,用来指定使用的协议类型,可以是IPPROTO_TCP等 int protocol); type 参数用来指定套节字的类型。套节字有流套节字、数据报套节字和原始套节字等,下面是常见的几种套节字类型定义:SOCK_STREAM 流套节字,使用TCP协议提供有连接的可靠的传说SOCK_DGRAM 数据报套节字,使用UDP协议提供无连接的不可靠传输SOCK_RAW 原始套节字,Winsock接口并不使用某种特定的协议去封装它,而是有程序的自行处理数据报以及协议首部。当type参数指定为SOCK_STREAM和SOCK_DGRAM时,系统已经明确确定使用UDP协议来工作,所以protocol参数可以指定为0。函数执行失败返回INVYLID_SOCKET(即-1),可以通过调用WSAGetLasError取得错误代码。当不使用socket创建的套节字时,应该调用closesocket函数将它关闭。如果没有错误发生,函数返回0,否则返回SOCKET_ERROR。函数用法如下:int closesocket(SOCKET s); /函数唯一的参数就是关闭的套节字的句柄该过程的核心程序代码如下:if(ServerSock!=0)closesocket(ServerSock); /关闭套接字ServerSock=0;if(ServerSock=0)/创建套接字对象,数据报套接字,SOCK_STREAM为流套接字/建立套接字失败if(ServerSock=socket(AF_INET,SOCK_DGRAM,0)=SOCKET_ERROR)MessageBox(NULL,Set Socket Failed!,Error,0);3.1.3 绑定套节字到指定的IP地址和端口号成功创建了Socket之后,就应该选定通信的对象。首先是自己的程序要与网上的哪台计算机通话;其次,在多任务的系统下,该台计算机上可能会有几个程序在工作,必须指出要与哪个程序通信。前者可以通过IP地址来确定,而后者则由端口号来确定的。为套节字关联本地地址的函数是bind,函数原形如下:int bind( SOCKET s , /套节字句柄 const struct sockaddr * name, /要关联的本地地址 int namelen); /地址的长度bind 函数用在没有建立连接的套节字上,它的作用是绑定面向连接的或者无连接的套节字。当一个套节字被socket函数创建之后,它存在于指定的地址家族里,但是它是名命名的。bind 函数通过安排一个本地名称到未命名的socket建立此socket的本地关联。本地名称包含3个部分:主机地址、协议号和端口号。将套节字与IP地址和端口号绑定的核心程序代码:ServerAddr.sin_family=AF_INET;/系统自动使用当前主机配置的所有IP地址ServerAddr.sin_addr.S_un.S_addr=INADDR_ANY;serPort=GetDlgItemInt(hDlg,IDC_Sport,&serErr,TRUE);ServerAddr.sin_port=htons(u_short)serPort); /bind()绑定套接字在指定的端口if(bind(ServerSock,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr)=SOCKET_ERROR)MessageBox(NULL,Bind Port Failed!,Error,0);return 1;3.1.4 设置套节字进入监听状态listen 函数置套节字进入监听状态。int listen( SOCKET s, /套节字句柄 int backlog);/监听队列中允许保持的尚未处理的最大连接数量为了接受连接,首先使用socket函数创建一个套节字,然后使用bind 函数绑定它到一个本地地址,再使用listen 函数为到达的连接指定一个backlog,最后使用accept接受请求的连接。listen 仅应用在支持连接的套节字上,如SOCK_STREAM类型。函数成功执行后,套节字s 进入了被动模式,到来的连接会被通知,排队等接受处理。在同一时间处理对个连接请求的服务器通常使用listen 函数:如果一个连接请求到达,并且排队已满,客户端将接收WSAECONNREFUSED错误。在基于UDP协议的网络聊天室设计中,不需要listen 函数,而这里的listen 监听知识绑定一个端口。其核心代码如下:ServerSocket = socket(AF_INET, SOCK_DGRAM, 0);if (ServerSocket = INVALID_SOCKET ) MessageBox(NULL,” socket创建失败”,”Error”,0);return false;srv.sin_family = AF_INET;srv.sin_addr.s_addr = htonl( INADDR_ANY );/ 任何地址srv.sin_port = htons( PortNum );if ( bind(ServerSocket, (struct sockaddr *)&srv, sizeof(srv) != 0 )MessageBox(NULL,” socket绑定端口失败”,”Error”,0);closesocket( ListenSocket );return false;3.1.5 收发数据对数据报套节字来说,一般使用sendto和recvfrom函数来收发数据。在这次网络聊天室的设计中,我们采用服务器只接收数据而不进行转发数据,从而简化了部分任务,不过其核心功能还是实现的很好。recvfrom()/sendto()的函数原型如下:int recvfrom ( SOCKET s,char FAR* buf, int len,int flags,struct sockaddr FAR* from, int FAR* fromlen );int sendto (SOCKET s,const char FAR * buf, int len, int flags,const struct sockaddr FAR * to, int tolen);使用说明:s:是连接用的socket。buf、len:发送或接收的数据包字符串的地址和长度。flags:一般取0。from、fromlen/to、tolen:含义和用法与bind()中的相同,分别表示接收和发送数据的对象。实现该功能的核心程序代码入下:case IDC_receive: /接受按钮的ID号/接受数据的对象recvfrom(ServerSock,Output,256,0,(LPSOCKADDR)&ServerAddr,&fromlen);SetDlgItemText(hDlg,IDC_Sedit1,Output);return 1;3.1.6 关闭连接这个模块主要实现的功能包括关闭由socket创建的数据报套节字、释放Winsock库和清除一个模态对话框,并使系统中止对对话框的任何处理。实现这几个功能的函数为:closesocket()、WSACleanup()和EndDialog()函数。实现这些功能的程序代码如下:case IDC_closeserver: closesocket(ServerSock);WSACleanup(); /释放Winsock库/清除一个模态对话框,并使系统中止对对话框的任何处理EndDialog(hDlg,TRUE); return 1;3.2 客户端程序设计客户端程序的设计思路和服务器端有很大的相似之处,只不过客户端不需要绑定IP地址和端口号,也不需要进行监听功能。所以,在总体设计上,比服务器端稍微简单一点,与服务器的实现原理是相同的。客户端程序的设计中也要由socket创建数据报套节字,还要用sendto()发送数据,最后要关闭套节字,释放Winsock库。在客户端,数据方式(UDP协议)构建网络聊天室程序设计中,Winsock库德载入和初始化,创建套节字等功能和服务器端的完全相同,在这里就不再重复。不同之处在与客户端要发送数据而不进行接收数据。3.2.1 发送数据程序设计【函数原型】int sendto (SOCKET s,const char FAR * buf, int len, int flags,const struct sockaddr FAR * to, int tolen);【使用说明】s:是连接用的socket。buf、len:发送或接收的数据包字符串的地址和长度。flags:一般取0。from、fromlen/to、tolen:含义和用法与bind()中的相同,分别表示接收和发送数据的对象。实现发送数据的核心程序代码如下:case IDC_send: /发送按钮的ID号ClientAddr.sin_family=AF_INET;ClientAddr.sin_addr.S_un.S_addr=inet_addr(IPStr);ClientPort=GetDlgItemInt(hDlg,IDC_Eport,&bErr,TRUE);ClientAddr.sin_port=htons(u_short)ClientPort);/使用指定的 SocketFlags,将指定字节数的数据发送到指定的终结点sendto(ClientSocket,InputText,256,0,(LPSOCKADDR)&ClientAddr,sizeof(ClientAddr);break;3.2.2 几个关键结构体的介绍在整个基于UDP协议的网络聊天室程序设计中,我们一直都在使用几个比较重要的系统自定义的结构体,我们正是在这些结构体的基础上进行程序设计,并最终完成网络聊天室的设计。在这里主要介绍Sockaddr_in结构体和IP地址sin_addr结构体。Sockaddr_in的定义如下:struct sockaddr_in short sin_family; unsigned short sin_port; struct in_addr sin_addr; char sin_zero8;其中,sin_family是指一套地址族,它指定所要使用的通信协议,通常设为AF_INET;sin_port端口号;sin_addr是IP地址;而sin_zero8的作用,只是使该结构的大小和SOCKADDR结构大小相同。IP地址sin_addr结构定义如下:struct in_addr union struct u_char s_b1,s_b2,s_b3,s_b4; S_un_b; struct u_short s_w1,s_w2; S_un_w; u_long S_addr; S_un;这样,对于一个IP地址,例如“192.168.0.1”,就可以用以下三种方法赋给一个sockaddr结构体(例如struct sockaddr_in m_addr;):方法1:m_addr.sin_addr.S_un.S_un_b.s_b1=192;m_addr.sin_addr.S_un.S_un_b.s_b2=168;m_addr.sin_addr.S_un.S_un_b.s_b3=0;m_addr.sin_addr.S_un.S_un_b.s_b4=1;方法2:m_addr.sin_addr.S_un.S_un_w.s_w1=(1688)|192;m_addr.sin_addr.S_un.S_un_w.s_w2=(18)|0;方法3:m_addr.sin_addr.S_un.S_addr=(124)|(016)|(1688)|192;为了更方便地赋值,winsock还为我们提供了一个函数inet_addr(),可以把用字符串表示的IP地址“192.168.0.1”直接赋给结构体m_addr:char * IP_String=”192.168.0.1”;m_addr.sin_addr.S_un.S_addr=inet_addr(IP_String);4 程序界面设计4.1 服务器端界面设计在服务器界面中,主要有一个接收数据的窗口,另
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 29730-2025冷热水用分集水器
- GB/T 13790-2025搪瓷用冷轧低碳钢板及钢带
- 2025年残联会计准则实施能力模拟题
- 2025年科协会计考试模拟题及重点难点解析
- 2025年家政服务技能实操高级考核题集
- 2025年本科院校审计处面试模拟题及答案集
- 2025年充电桩运维工笔试模拟考试题
- 2025年安全员模拟测试题及答案练习册
- 2025年汽车美容技师技能认证考试试题及答案解析
- 2025年金融风控专家资格考试试题及答案解析
- 三农村电商创业融资指导手册
- 国际商务课件全套教程
- 22.3 实际问题与二次函数 课件 2024-2025学年人教版数学九年级上册
- 文言合集(1):120个文言实词小故事(教师版+学生版)
- 教科版(2024)小学科学一年级上册(全册)教案及反思(含目录)
- 【课件】2025届高三生物一轮复习备考策略研讨
- 中级会计师《经济法》历年真题及答案
- 新疆城市绿地养护管理标准
- 高职院校高水平现代物流管理专业群建设方案(现代物流管理专业群)
- 汉语言文学毕业设计开题报告范文
- 爱自己爱生命主题班会课件
评论
0/150
提交评论