套接字网络编程.docx
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 套接 网络 编程
- 资源描述:
-
18.3 | Windows套接字技术 套接字(Socket)是网络通信的基本构件,最初是由加利福尼亚大学Berkeley学院为UNIX开发的网络通信编程接口,它只能运行在UNIX操作系统,不支持DOS和Windows操作系统。随着Windows操作系统的日益推广,90年代初,微软和第三方厂商共同制定了一套标准,即Windows Socket规范,简称WinSock。本节将介绍有关Windows套接字的相关技术。 18.3.1 套接字概述 套接字的概念与文件句柄类似,一个套接字就是一个通信标识,由一个短整数表示,实际上就是一个句柄,代表网络协议中的一组数据,该数据包含了通信双方的IP地址和当前的连接状态等信息。我们知道,如果一个文件被打开,可以通过文件句柄对文件进行读写操作,套接字也一样,只不过套接字提供的函数更多一些。 套接字存在于通信区域中,由协议、地址、端口来描述并惟一确定,根据传输协议的不同,套接字可分为3种类型:流式套接字、数据报套接字和原始套接字。流式套接字提供了一个面向连接的、可靠的、数据无错且按顺序接收的服务,这种套接字对应的是面向连接的传输协议,如TCP/IP协议簇中的TCP。数据报套接字提供了一个无连接服务,不提供无错保证,数据可能丢失或重复,且接受顺序混乱,该套接字所对应的是无连接传输协议,如TCP/IP协议簇中的UDP。原始套接字允许直接访问低层的协议,如IP、ICMP协议,该套接字常用于访问服务器中配置的新设备。 18.3.2 WinSock API相关函数 WinSock提供了许多套接字函数,它们并不代表协议的某一个层次,其实质就是一组编程接口,用户利用这些函数可以很容易地进行编程。 (1)socket函数 socket函数用于创建一个套接字。 语法: SOCKET socket ( int af, int type, int protocol ); af:标识一个地址家族,通常为AF_INET。 type:标识套接字类型,如果为SOCK_STREAM,表示流式套接字;如果为SOCK_DGRAM,表示数据报套接字。 protocol:标识一个特殊的协议被用于这个套接字,通常为0,表示采用默认的TCP/IP协议。 (2)accpet函数 accpet函数用于接受客户端的连接请求。返回值是一个新的套接字,它对应于已经接受的客户端连接,对于该客户端的所有后续操作,都应使用这个新的套接字。 语法: SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen ); s:是一个套接字,它应处于监听状态。 addr:是一个sockaddr_in结构指针,包含一组客户端的端口号、IP地址等信息。 addrlen:用于接收参数addr的长度。 (3)bind函数 bind函数用于将套接字绑定到一个已知的地址上。如果函数执行成功,返回值为0,否则为SOCKET_ERROR。 语法: int bind ( SOCKET s, const struct sockaddr FAR* name, int namelen ); s:是一个套接字。 name:是一个sockaddr结构指针,该结构中包含了要绑定的地址和端口号。 namelen:确定name缓冲区的长度。 在定义一个套接字后,需要调用bind函数为其指定本机地址、协议和端口号。 例如,创建一个套接字s,将其绑定到3010端口上,其代码如下: int port = 3010; SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_IP); sockaddr_in addr; addr.sin_family = AF_INET; //内部网络协议TCP/UDP等 addr.sin_port = htons(port); //端口号 addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(s,(LPSOCKADDR)&addr,sizeof(addr))==0) { MessageBox("成功"); } (4)closesocket函数 closesocket函数用于关闭某个套接字。 语法: int closesocket ( SOCKET s ); s:标识一个套接字。如果参数s设置有SO_DONTLINGER选项,则调用该函数后会立即返回,但此时如果有数据尚未传送完毕,会继续传递数据,然后才关闭套接字。 (5)connect函数 connect函数用于发送一个连接请求。如果函数执行成功,返回值为0,否则为SOCKET_ERROR。用户可以通过WSAGetLastError得到其错误描述。 语法: int connect ( SOCKET s, const struct sockaddr FAR* name, int namelen ); s:标识一个套接字。 name:套接字s想要连接的主机地址和端口号。 namelen:name缓冲区的长度。 (6)htons函数 htons函数将一个16位的无符号短整型数据由主机排列方式转换为网络排列方式。 语法: u_short htons ( u_short hostshort ); hostshort:一个主机排列方式的无符号短整型数据。 (7)htonl函数 htonl函数将一个32位的无符号长整型数据由主机排列方式转换为网络排列方式。 语法: u_long htonl ( u_long hostlong ); hostlong:一个主机排列方式的无符号长整型数据。 (8)inet_addr函数 inet_addr函数将一个由字符串表示的地址转换为32位的无符号长整型数据。 语法: unsigned long inet_addr ( const char FAR * cp ); cp:一个表示IP地址的字符串。 (9)listen函数 listen函数用于将套接字置入监听模式。 语法: int listen ( SOCKET s, int backlog ); s:套接字。 backlog:表示等待连接的最大队列长度。例如,如果backlog被设置为3,此时有4个客户端同时发出连接请求,那么前3个客户端连接会放置在等待队列中,第4个客户端会得到错误信息。 (10)recv函数 recv函数用于从连接的套接字中返回数据。 语法: int recv ( SOCKET s, char FAR* buf, int len, int flags ); recv函数参数的说明如表18.5所示。 表18.5 recv函数参数说明 参 数 名 称 参 数 描 述 S 标识一个套接字 Buf 是接收数据的缓冲区 Len 是buf的长度 Flags 表示函数的调用方式,可选值如下: MSG_PEEK_用来查看传来的数据,在序列前端的数据会被复制一份到返回缓冲区中,但是这个数据不会从序列中移走 MSG_OOB_用来处理Out-Of-Band数据 (11)select函数 select函数用来检查一个或多个套接字是否处于可读、可写或错误状态。 语法: int select ( int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout ); select函数参数说明如表18.6所示。 表18.6 select函数参数说明 参 数 名 称 参 数 描 述 nfds 没有实际意义,只是为了和UNIX下的套接字兼容 readfds 标识一组被检查可读的套接字 writefds 标识一组被检查可写的套接字 exceptfds 是被检查有错误的套接字 timeout 标识函数的等待时间 (12)send函数 send函数在已经建立连接的套接字上发送数据。 语法: int send ( SOCKET s, const char FAR * buf, int len, int flags ); send函数参数说明如表18.7所示。 表18.7 send函数参数说明 参 数 名 称 参 数 描 述 s 标识一个套接字 buf 是存放要发送数据的缓冲区 len 标识缓冲区长度 flags 标识函数的调用方式 (13)WSAStartup函数 WSAStartup函数用于初始化WS2_32动态库。它应该是应用程序第1个调用的Windows Socket函数,用于确定Windows Socket使用的版本。 语法: int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData ); wVersionRequested:标识调用者使用的Windows Socket的版本,高字节记录修订版本,低字节记录主版本。例如,如果Windows Socket的版本为2.1,则高字节记录1,低字节记录2。 lpWSAData:记录Windows Socket的详细信息。 下面的代码用于确定Windows Socket使用的版本。 WSADATA wsd; WSAStartup(MAKEWORD(2,2),&wsd); (14)WSACleanup函数 WSACleanup函数与WSAStartup函数是相对的,用于终止使用WS2_32动态库。 语法: int WSACleanup (void); 说明: 当Windows Socket使用完成时,应调用WSACleanup函数释放分配给应用程序或动态库的资源。 (15)WSAAsyncSelect函数 WSAAsyncSelect函数用于将网络中发生的事件关联到窗口的某个消息中。 语法: int WSAAsyncSelect ( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent ); WSAAsyncSelect函数参数说明如表18.8所示。 表18.8 WSAAsyncSelect函数参数说明 参 数 名 称 参 数 描 述 s 标识套接字 hWnd 标识窗口句柄 wMsg 标识窗口消息 lEvent 标识网络中的事件 18.3.3 使用套接字函数设计网络聊天室 在18.3.2节中笔者介绍了常用的套接字函数,接下来将利用这些套接字函数设计一个网络聊天室程序。程序由两个实例组成,第1个实例为服务器端,负责接收用户的连接请求,并转发用户信息。第2个实例为客户端,负责连接服务器并发送信息。 服务器端程序设计步骤如下: ch1806实例位置:mr/18/sl/06 (1)创建一个基于对话框的应用程序,设计对话框资源如图18.11所示。 (2)在对话框的头文件中引用“winsock2.h”头文件,并导入网络库文件。 #include "winsock2.h" #pragma comment (lib,"ws2_32.lib") (3)在应用程序的InitInstance方法中初始化套接字。 WSADATA wsd; WSAStartup(MAKEWORD(2,2),&wsd); (4)在对话框类中定义成员变量,记录服务器套接字和与之连接的客户端套接字信息。 SOCKET m_server,m_client; SOCKET m_Clients[MAXNUM]; //客户端套接字 int m_CurClient; //当前连接的客户数量 (5)在对话框类的OnInitDialog方法中创建套接字,并初始化数据。 //创建套接字 m_server = socket(AF_INET,SOCK_STREAM,0); //将网络中的事件关联到窗口的消息函数中 WSAAsyncSelect(m_server,m_hWnd,20000,FD_WRITE|FD_READ|FD_ACCEPT); m_client = 0; m_serverIP = ""; for (int i = 0; i< MAXNUM;i++) m_Clients[i]= 0; m_CurClient = 0; (6)处理“监听”按钮的单击事件,将套接字绑定到本机地址,并开始监听套接字。 void CServerDlg::OnOK() { //服务器端地址 sockaddr_in serveraddr; serveraddr.sin_family = AF_INET; m_IP.GetWindowText(m_serverIP); //设置本机地址 serveraddr.sin_addr.S_un.S_addr = inet_addr(m_serverIP); UpdateData(TRUE); //设置端口号 serveraddr.sin_port = htons(m_port); //绑定地址 if (bind(m_server,(sockaddr*)&serveraddr,sizeof(serveraddr))) { MessageBox("绑定地址失败."); return; } //开始监听 listen(m_server,50); } (7)向对话框中添加HandleData方法,用于接受客户端的连接,并获得客户端传来的数据,将其转发给其他客户端。 void CServerDlg::HandleData() { sockaddr_in serveraddr; char buffer[1024]; int len =sizeof(serveraddr); //接收客户端的数据 int curlink = -1; int num = -1; for (int p = 0;p< MAXNUM; p++) { num= recv(m_Clients[p],buffer,1024,0); if (num != -1) { curlink = p; break; } } buffer[num]= 0; if (num==-1) //接受客户端的连接 { if (m_CurClient < MAXNUM) { m_Clients[m_CurClient] = accept(m_server,(struct sockaddr*) &serveraddr,&len); m_CurClient+=1; } return; } //将接收的数据发送给客户端 for (int j = 0;j< m_CurClient;j++) if (j != curlink) send(m_Clients[j],buffer,num,0); } (8)改写对话框类的PreTranslateMessage方法,在服务器套接字中有事件触发时调用HandleData方法。 BOOL CServerDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->message==20000) { HandleData(); return TRUE; } else return CDialog::PreTranslateMessage(pMsg); } 客户端程序设计步骤如下。 ch1807实例位置:mr/18/sl/07 (1)创建一个基于对话框的工程,设置对话框资源如图18.12所示。 图18.12 客户端设计窗口 (2)在对话框类的头文件中引用“winsock2.h”头文件,并导入“ws2_32.lib”库文件。 #include "winsock2.h" #pragma comment (lib,"ws2_32.lib") (3)在应用程序的InitInstance方法中初始化套接字。 WSADATA wsd; WSAStartup(MAKEWORD(2,2),&wsd); (4)在对话框的OnInitDialog方法中创建套接字。 m_client = socket(AF_INET,SOCK_STREAM,0); (5)处理“连接”按钮的单击事件,连接服务器,并设置套接字接收数据时触发的消息。 void CClientDlg::OnOK() { //服务器端地址 sockaddr_in serveraddr; UpdateData(TRUE); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(m_port); serveraddr.sin_addr.S_un.S_addr = inet_addr(m_IP); if (connect(m_client,(sockaddr*)&serveraddr,sizeof(serveraddr))!=0) { MessageBox("连接失败"); return; } else MessageBox("连接成功"); WSAAsyncSelect(m_client,m_hWnd,1000,FD_READ); CString str,info ; m_name.GetWindowText(str); info.Format("%s------>%s",str,"进入聊天室"); int i = send(m_client,info.GetBuffer(0),info.GetLength(),0); } (6)处理“发送”按钮的单击事件,向服务器发送数据。 void CClientDlg::OnButton1() { CString str,name,info ; m_name.GetWindowText(name); m_info.GetWindowText(str); if (!name.IsEmpty()&&!str.IsEmpty()) { info.Format("%s说: %s",name,str); //开始发送数据 int i = send(m_client,info.GetBuffer(0),info.GetLength(),0); m_list.AddString(info); m_info.SetWindowText(""); } } (7)向对话框类中添加ReceiveData方法,用于接收从服务器传来的数据。 void CClientDlg::ReceiveData() { char buffer[1024]; //接收服务器端传来的数据, int num = recv(m_client,buffer,1024,0); buffer[num] = 0; //将接收的数据添加到列表框中 m_list.AddString(buffer); } (8)改写对话框的PreTranslateMessage方法,截获对话框的消息,用于接收数据。 BOOL CClientDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->message==1000) { ReceiveData(); return TRUE; } else return CDialog::PreTranslateMessage(pMsg); }展开阅读全文
咨信网温馨提示:1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。




套接字网络编程.docx



实名认证













自信AI助手
















微信客服
客服QQ
发送邮件
意见反馈



链接地址:https://www.zixin.com.cn/doc/6866445.html