异步SOCKET编程-发送和接收数据[转] 异步SOCKET编程-发送和接收数据[转]
原本打算将发送与接收分开作为两个部分。
然而最终决定只需对FD_READ稍作介绍。
当数据发送过来时,在这里你会得到一个FD_READ事件。
每当发生一个FD_READ事件时,请按照下面的方式调用recv函数。
int bytes_recv = recv(wParam, &data, sizeof(data), 0);
基本上就是这个样子, 别忘了修改上方的wParam. 另外, 有时候调用recv()可能会不立刻返回一个完整的数据包, 因为数据传输可能不是一次性完成的. 因此,在处理接收到的数据之前最好先检查接收的数据字节数(即recv()返回的值),确认是否已经收到了完整的一份数据包.
当创建一个文件描述符(FD)并开始传输数据后, 会触发一次FD_WRITE事件. 然而, 如果误以为接收到该事件就意味着传输操作已完成并忽略后续步骤, 这样就会导致传输过程出现错误. FD_WRITE事件只会在此处存在缓冲区剩余空间且能够接收新数据的时候才会被触发.
所谓发送缓冲区的概念,实际上源自系统底层提供的缓冲区空间。send()操作首先将数据注入发送缓冲区,随后通过网络将数据传输至接收端。然而这种想法并不完全正确。即使保持足够的空位以供新数据填充,FDWRITE事件也不会持续产生。别着急.实际上.FDWRITE事件仅会在存在未被占用的空间时触发.换句话说.只有当发送缓冲区已满时才会停止产生FDWRITE事件。
常规的做法是在一个无限循环中持续不断地向目标发送数据直至数据缓冲区已满载状态。一旦数据缓冲区达到饱和状态调用send函数将会导致 SOCKET _ERROR异常发生同时Windows操作系统提供的WSAGetLastError函数将会返回WA SWOULDBLOCK错误信息。如果当前这个 SOCKET 处于阻塞模式程序必须持续等待直至缓冲区空闲才能继续执行数据传输操作;而如果该 SOCKET处于非阻塞状态则会出现WA SWOULDBLOCK错误异常。因此为了确保流程顺利运行建议首先通过不断调用send函数直到数据缓冲区已满载状态随后当缓冲区空闲时系统将会触发FD_WRITE事件这一机制能够有效避免死锁问题的发生。是否曾想过这项功能的设计难度之高令人叹为观止?运气真好。下面将提供一个详细的FD_WRITE事件处理示例供参考。
case FD_WRITE: // 开始发送数据
注
// 发送操作
if (send(wparam, (char*)(&packet), sizeof(PACKET), 0) == SOCKET _ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
// 发送缓冲区已满已触发报错机制
执行break语句
}
else
{
// 错误信息已显示后执行CleanUp()并返回程序结束码
调用CleanUp函数;
Cause程序终止;
}
}
已经看到了!实际上只是对某些概念存在误解。采用这种发送机制,在缓冲区达到满载状态时自动终止循环。接着,在检测到缓冲区空闲时触发另一个FD_WRITE事件后,则可继续进行数据传输。
在尝试应用新知识之前,请让我补充一点关于FD_WRITE事件的知识。如果您的场景并不是一次性发送大量数据的情况,则无需考虑使用FDWRITE事件这一策略。原因很简单:系统只会触发一次FDWRITE事件;如果期望在收到该事件后立即发送数据,并且无法一次性将足够的数据填满传输缓冲区,则只能捕捉到刚建立连接时触发的那一波FDWRITE事件;系统不会再触发后续的FDWRITE事件。因此,在发送少量数据时无需依赖FDWRITE机制,在任何需要发送数据的情况下直接调用send()函数即可。
结论
这篇是我历时最长完成的长文. 我也曾在努力缩短篇幅以引起您的关注, 却不得不包含大量的内容. 当我初次运用异步****SOCKET技术时, 真的是让我不知所措. 希望通过这篇文章能让你掌握这些技术要点。
这是 GOOGLE 文档中的一段文字内容。尽管原作者的一些观点看似不正确, 但文章整体较为易懂。实际上,在希望接收FD_WRITE事件却无法预先填满发送缓冲区的情况下,则可以调用WSAAsyncSelect函数(..., FD_WRITE)。当发送缓冲区还有空间时,则系统将立即分配一个FD_WRITE事件。
在MFC环境中,CAsyncSocket类将FD_WRITE消息配置为OnSend函数. 在MFC环境中,CAsyncSocket类将FD_READ消息配置为OnReceive函数.
飞不动的鸟 在2006年4月29日上午十时零八分发布于《C++博客》(http://www.cppblog.com/noflybird)
这篇文章被阅读了143次
共有1条评论
您可以在此对文章进行编辑(EditPosts)或加入 favorites(AddToFavorites)
2006年4月27日 #
**Socket(套接字)
** ◆先看定义:
socket类似于网络通信两端的连接端口,在双方socket之间建立通信连接后即可实现数据传输功能。只有当双方socket之间存在通信连接时才可以完成数据发送与接收操作。其定义与文件句柄类似
◆Socket有五种不同的类型:
1、流式套接字(stream socket)
定义:
流式套接字提供了双端、有序排列且具有唯一性保证的数据流服务,并特别适合处理海量数据。它作为一个连接型架构,在传输过程中需要预先建立传输通道,并在传输过程中还需要实施数据验证机制以确保准确性和可靠性。由此带来的系统开销相对较高。
2、 数据报套接字(datagram socket)
定义:
该套接口具备双向传输通道的能力,并非绝对保证信息传输的完整性;然而它仍然保留了事件的时间戳信息。因为其设计特性决定了无法同时处理多个信号源;因此,在广播场景下使用的多路访问机制会导致接收端可能无法实时检测到发送操作的存在;与传统点对点通信方式相比,在高效性方面表现更为突出。
3、原始套接字(raw-protocol interface)
定义:
负责完整地保存了数据包中的IP头字段,在此之前使用的前两种类型的套接字仅限于接收用户的原始数据。因此可利用该原始套接字来进行数据分析。除此之外的其他两种类型套接字由于其不常用性而未做详细讲解。
◆Socket开发所必须需要的文件(以WinSock V2.0为例):
头文件:Winsock2.h
库文件:WS2_32.LIB
动态库:W32_32.DLL

一些重要的定义
1、数据类型的基本定义:这个大家一看就懂。
网络地址的数据结构中存在两种不同的表示方法:传统的网络地址数据结构与现代的不同。想要了解原因的话,请联系Bill Gate。实际上这是计算机中的IP地址概念。然而通常不采用点分法来表示IP地址,并且提供了一些转换工具供使用。
◆ 旧的网络地址结构的定义,为一个4字节的联合:
其实完全不用这么麻烦,请看下面:
新的网络地址结构的定义
3、 套接字地址结构
(1)、sockaddr结构:
sa_family是一种网络地址类型,通常为AF_INET类型,在TCP/IP协议下用于表示该socket在Internet域中进行通信。由于该地址架构会根据所选协议的不同而有所变化,在大多数情况下,另一个与该地址架构大小相当的sockaddr_in类型的地址更为常用。换句话说,这个架构可被视为通用socket地址架构,在下面提及的具体应用场景中,则采用专门针对Internet域设计的sockaddr_in架构。
(2)、sockaddr_in结构
sin _family应指定网络地址族类型。
sin_port必须被配置设为AF_INET。
注意避免使用已被预先定义的服务端口号(例如HTTP协议使用的80号位)。
若指定该值,则系统将自动生成唯一的默认值。
sin_addr应定义为其对应的数据类型的IP地址。
sin_zero仅用于确保数据完整性。
◆ 将常用的用点分开的IP地址转换为unsigned long类型的IP地址的函数:
用法:
如果将sin_addr配置为INADDR_ANY,则表示所有有效的IP地址,并表示所有接入的计算机。
4、 主机地址:
先看定义:
另外还有几个类似的结构,这里就不一一介绍了。
5、 常见TCP/IP协议的定义:
具体是什么协议,大家一看就知道了。

套接字的属性
为了灵活使用套接字,我们可以对它的属性进行设定。
1、 属性内容:
2、 读取socket属性:
s表示欲读取属性的套接字。level代表套接字选项的级别,默认情况下属于特定协议或专用的套接字类型。例如,在IP协议中通常使用的是 IPPROTO_IP。
用法:
3、 设置socket属性:
s为目标属性的套接器标识。\nlevel表示套接字相关的选项层级,并遵循相同的用法。\noptname指定用于配置的各项选项名称。\noptval指示用于存储各选项值的数据缓冲区域的位置。\noptlen记录数据缓冲区的实际容量大小。
用法:

套接字的使用步骤
配置Winsock服务以支持...确保所需资源得到合理分配(服务器端和客户端)
如果加载成功后数据为:
该函数使用方法:
2、创建套接字:(服务器端和客户端)
用法:
3、套接字的绑定:将本地地址绑定到所创建的套接字上。(服务器端和客户端)
用法:
4、 套接字的监听:(服务器端)
s是一个已绑定但尚未完成套接字的实例。
backlog参数定义了服务器处理请求的最大队列长度。这一参数对于系统的负载管理至关重要;由于其限制了服务器同时处理请求的数量, 因此通常情况下会设置较高的值以支持多线程或分布式服务。
用法:
5、套接字等待连接::(服务器端)
s是处于监听状态的套接字。sockaddr响应客户端获取网络地址。addrlen表示网络地址的长度。
用法:
6、套接字的连结:将两个套接字连结起来准备通信。(客户端)
s被用作连接已建立的socket。
name表示欲连接的目标socket地址。
namelen表示用于标识目标socket地址结构的部分长度。
用法:
7、套接字发送数据:(服务器端和客户端)
s表示服务器端用于接收连接的套接字标识。
buf为目标数据缓冲区头的指针变量。
len表示目标缓冲区中可传输的数据长度。
flags用于标识与数据传输相关的关键信息字段。
该函数返回成功发送的数据字符数量。
◆这里讲一下这个发送标记,下面8中讨论的接收标记也一样:
flag取值必须为0或者如下定义的组合:0表示没有特殊行为。
#define OOBMsg 0x1 /* 处理带外数据 /
#define PEKMsg 0x2 / 检视入站消息 /
#define DNCMsg 0x4 / 不使用路由表发送包 */
MSG_OOB标识着数据应当进行带外发送;所谓带外数据即为TCP紧急数据。
MSG_PEEK则表示使有用的数据被复制到缓冲区中。
MSG_DONTROUTE则指示不要将包进行路由。
用法:
8、 套接字的数据接收:(客户端)
s是负责接收数据连接的一端套接字。buf是用于存储接收到的数据块的临时存储区域。len是用于表示准备接收的数据缓冲区大小的一个变量。flags作为标志位字段使用。该字段会返回在读取操作中成功捕获到的有效字符数量。
用法:
中断套接字连接用于指示服务器端或客户端停止接收与发送数据。(服务器端和客户端)
s表示欲中断连接的套接字变量。How被用来描述禁止哪些操作?其取值包括接收同步、发送同步以及双向同步。
用法:
10、 关闭套接字:释放所占有的资源。(服务器端和客户端)
s为欲关闭的套接字。
用法:
非鸟类发布于2006年4月27日上午9:31. 题目为《不会飞的鸟》,访问量:221次. 评论数量:0条. 编辑中. 已收藏. permalink: http://www.cppblog.com/noflybird/archive/2006/04/27/6362; 点评, 点评, trackbacks: comments, pingbacks, trackbacks; 编辑地址: http://www.cppblog.com/noflybird/admin/EditPosts.aspx?postid=6362; 收藏地址: http://www.cppblog.com/noflybird/AddToFavorite.aspx?id=6362
**与socket有关的一些函数介绍
获取当前错误信息:在每次出现错误时,在为了处理具体的问题这一目标下,则会调用该函数以取得对应的出错码。
错误值请自己阅读Winsock2.h。
将主机的无符号长整数值转换为网络字节顺序(32位):那么这样做的原因是什么呢?由于不同类型的计算机采用不同的字节排列方式来存储数据。因此,在调用WinSock函数引用或传递IP地址及端口号时,请确保它们都是按照网络字节顺序组织。
用于将unsigned long数从网络字节顺序转换成主机字节顺序的操作, 是上述函数的反操作
4、将主机的unsigned short值转换为网络字节顺序(16位):原因同2:
将无符号short型数据从网络字节排列转换为主机字节排列,并对应于该函数的反向操作
将用点分隔符分割的IP地址转换为一个in_addr结构的字段值,请参阅笔记(一),其中该字段值本质上就是一个无符号长整型数值。然而,在这种情况下,请注意计算机内部处理IP地址却无法识别诸如192.168.1.1之类的数据。
如果发生错误,函数返回INADDR_NONE值。
7、将网络地址转换位用点分割的IP地址,是上面函数的逆函数。
经过设置后, addr被赋予了IP地址127.0.0.1
8、获取套接字的本地地址结构:
9、获取与套接字相连的端地址结构:
10、获取计算机名:
11、根据计算机名获取主机地址:

Winsock 的I/O操作:
1、 两种I/O模式
- 阻塞型的套接字:在完成I/O操作之前始终保持着等待状态,在任何情况下都不会将执行权限移交给调用方。默认采用阻塞型的套接字。
- 非阻塞型:在执行I/O操作时 Winsock 函数会在尚未完成任务时立即返回并释放本进程的执行权限 这种设计使得调用者必须及时处理可能出现的异常情况。
为了有效解决这一问题。为了有效解决这一问题。为了有效解决这一问题。
2、select模型:
利用select函数能够识别多个套接体的状态,并能检测该套体是否存在数据;此外还能够检查该套接受器是否接受新数据。
◆先来看看涉及到的结构的定义:
a、 d_set结构:
已预先配置好的socket总数由fd_count表示。该数组存储着所有连接到指定服务器的本地Socket实例;其中每一个元素都是一个完整的Socket对象。为了保证性能稳定性和连接可靠性,在实际应用中建议将最大容量FD_SETSIZE设置为至少64个;这一设定通常被建议采用
B、timeval结构:
tv_sec代表时间以秒计量。
tv_usec表示时间以毫秒表示。
该结构主要用于配置select()函数的时间间隔。
当将该结构赋值为(0,0)时,select()函数将立刻返回。
◆再来看看select函数各参数的作用:
-
nfds:没有任何用处,主要用来进行系统兼容用,一般设置为0。
-
readfds:等待可读性检查的套接字组。
-
writefds;等待可写性检查的套接字组。
-
exceptfds:等待错误检查的套接字组。
-
timeout:超时时间。
-
函数失败的返回值:调用失败返回SOCKET_ERROR,超时返回0。
这三个字段中至少一个字段值非空,并且该字段所对应的socket类型必然包含一个socket实例。
道理显而易见。
举例来说,在判断某个特定的socket是否具备可读性时,
我们可以使用以下方法:
◆I/O操作函数:主要用于获取与套接字相关的操作参数。
s被定义为与I/O操作相关的套接字。
cmd代表用于处理套接字的操作指令。
argp是一个指向命令参数的数据指针。
常见的命令:
3、WSAAsynSelect模型:
该模型也被广泛应用于异步I/O场景中。
应用能够通过单个套接字接收基于Windows消息的网络事件触发。
该实现过程主要通过以下步骤完成:首先调用WSAAsynSelect函数来设置套接字为非阻塞状态;其次,在Windows系统中注册相关的时间标记;最后指定用于处理事件的通知窗口。
一旦注册的时间触发,则对应的窗口会收到基于Windows消息的通知。
s表示需要进行事件通知的套接字;hWnd是用于接收消息的窗口句柄;wMsg为目标要接收的消息;lEvent作为掩码,用于指定应用程序关注的网络事件集合。
用法:要接收读写通知:
取消通知:
每当应用程序窗口hWnd捕获一条消息时,在wMsg.wParam字段中标识了用于通信的套接字编号。其中wMsg.lParam的低字字段则表明当前的网络操作状态。而wMsg.lParam的高字字段存储了传输过程中的错误信息。
WSAEventSelect模型类似于WSAAsynSelect模型,在主要区别在于当网络事件发生时会被发送到一个事件对象句柄而非被发送到一个窗口。
使用步骤如下:
a、 创建事件对象来接收网络事件:
该函数的返回结果是一个事件对象句柄,并包含两个工作状态:已触发(signaled)与未触发(nonsignaled)。此外还包含两个调节模式:手动调节(manual reset)与自动调节(auto reset)。默认情况下,默认的是未触发的状态以及手动调节模式。
通过将事件对象与套接字进行关联,并在注册事件后确保其状态从未传信状态转变为已传信状态。
s表示套接字
hEventObject代表刚创建的事件对象句柄
lNetworkEvents为其定义方式如前所述
c、I/O处理后,设置事件对象为未传信
Hevent为事件对象
成功返回TRUE,失败返回FALSE。
d、等待网络事件来触发事件句柄的工作状态:
lpEvent是事件句柄指针类型的变量
cEvent表示事件句柄的数量,其最大可能值定义为WSA_MAXIMUM_WAIT_EVENTS
fWaitAll用于指定等待的方式:当lpEvent数组中的所有事件对象均出现信号时才返回 TRUE;否则一旦任一事件出现信号就立即返回 FALSE
dwTimeout表示等待超时的时间长度,默认设置通常在几十到几百毫秒之间...
fAlertable指示该函数在完成执行后是否需要进行后续操作...
在引用事件数组中的事件时,应当使用WSAWaitForMultipleEvents函数返回的结果,并从该结果中减去预先声明的常量...以获得具体的引用索引。例如:
e、判断网络事件类型:
s被视为一个套接字
hEventObject被指定为目标事件对象
lpNetworkEvents被定义为用于记录网络事件及其错误代码的数据结构。
其结构定义如下:
f、关闭事件对象句柄:
调用成功返回TRUE,否则返回FALSE。
发布于[时间]
编辑
2006年4月25日 #
深入探讨了 Windows Socket API 在网络编程中的应用(三),本文将详细阐述 Windows.SOCKETS 1.1 程序实现的技术细节。
**一、简介
** WINDOWSO SKETS 是源自 Berkeley Sockets 的一个重要扩展,在继承其核心功能的同时又进行了诸多增强。这些新增功能主要包括向用户提供更多异步操作能力,并通过引入 Windows 消息机制实现了更加智能的网络事件处理能力。
WINDOWSO SKETS 由开发组件与运行组件两大模块构成:
开发组件:WINDOWSO SKETS 实现了文档存储与应用程序接口(API)引入库,并提供了相关头文件作为参考文档。
运行组件:WINDOWSO SKETS 提供了应用程序接口的动态链接库(WINSOCK.DLL)。

二、主要扩充说明 1、异步选择机制:
WINDOWS SOCKETS 通过其异步选择机制实现了对网络活动的选择管理功能。该机制基于消息驱动模型,在指定的应用程序窗口函数被触发前即可完成相关操作设置。具体而言,在使用该机制进行注册时,系统会根据指定的应用程序窗口函数接收到来自不同网络活动的通知,并提供相应的处理流程。
WINDOWS SOCKETS 提供了一个专门用于注册应用程序感兴趣特定类型网络活动的WAS Async Select(WAS AsyncSelect)接口功能。
该接口允许用户为指定的应用程序窗口函数建立 registration 对象,并在这些特定的 network activity 触发时发送通知信息给目标 window function。
接口的主要组成部分包括:
- register callback: 用于指定需要监听的具体 network activity 类型
- handle notification: 用于定义处理 network activity 通知的具体逻辑
- notification parameters: 包含与 network activity 相关的各种参数信息
hWnd:窗口句柄变量
wMsg:消息类型参数
lEvent:事件(包括事件的具体内容)
值: 含义如下:
FD_READ 用于接收数据(即读端准备好)时触发
FD_WRITE 用于发送数据(即发端准备好)时触发
FD_OOB 用于处理带外数据到达时触发
FD_ACCEPT 用于处理外部连接建立时触发
FD_CONNECT 用于连接建立完成时触发
FD_CLOSE 用于关闭连接时触发
例如:当套接字处于读端或发端准备状态时需及时响应相关操作,请看以下示例:
如果我们需要注销对套接字网络事件的消息发送,只要将 lEvent 设置为0
Block-based Berkeley Socket requests are inherently blocking. In contrast, Windows API also provides corresponding asynchronous interfaces (e.g., WSAAsyncGetXByY()).
3、阻塞处理方法
Windows Sockets在遇到应用程序套接字调用进入阻塞状态时会触发一个称为"HOOK"的例子程序来接管CPU资源以供其他应用程序运行;该例子负责接收并分配Windows消息从而确保其他应用程序仍能接收消息并获得控制权;
由于Windows作为一个非抢占式的多任务操作系统若某个程序未主动放弃对其控制权则其他程序将无法运行因此在开发基于Sockets的操作系统时通常建议避免使用阻塞操作;然而Sun公司所支持的Berkeley Sockets默认采用的是阻塞操作这使得其移植到Windows Sockets的过程中也必须保留这种功能;
在Windows Sockets实现中对无法立即完成的任务阻塞操作可采用以下方式进行处理:首先启动DLL初始化然后进入循环模式;在循环中该实例会发送相关Windows消息并通过检查当前Sockets调用状态来决定是否释放CPU资源(当然如果使用超线程机制则此问题将不存在);此外还可以通过调用WSACancelBlockingCall函数来取消当前处于阻塞状态的操作;
在Windows Sockets中预设了一个默认的Blocking Hook例子程序它简单地接收并发送Windows消息;如果需要自定义复杂的处理逻辑则可以通过WSASetBlockingHook函数来指定自定义的例子程序而与之对应的SWAUnhookBlockingHook函数则用于移除已设置的例子程序后重新启用默认行为请注意在设计自定义 Blocking Hook时除了使用WSACancelBlockingHook函数外还必须避免调用其他Sockets API函数以免影响系统的正常运作;
4、错误处理 Windows Sockets 为确保与后续多线程环境(Windows/UNIX)兼容性需求,在其机制中引入了两个错误处理功能模块。这些模块的主要作用是支持获取并设置当前进程最近出现的错误信息。(通过WSAGetLastError()和WSASetLastError()函数实现这一功能)
5、启动与终止
使用函数 WSAStartup() 和 WSACleanup() 启动和终止套接字。

三、WINDOWS SOCKETS 网络程序设计核心
目前我们已经准备好启动Windows Sockets网络程序设计工作。然而,在深入学习之前,请确保您了解每个Windows Sockets网络程序所包含的核心组件。让我们循序渐进地逐步深入学习这一技术。
1、启动与终止
在WINDOWS SOCKETS函数的应用中,默认情况下仅限于必须调用启动函数WSAStartup()和终止函数WSACleanup()这两个核心函数。为了确保系统正常运行,WSAStartup()必须作为第一个被调用的函数,它不仅能够指定所使用的WINDOWS SOCKETS API的具体版本,还能够获取SOCKETS类型的一些技术特性信息。其基本结构如下:
其中wVersionRequested确保SOCKETS能够正常运行所需的DLL版本号;如果无法支持,则会返回错误信息。
我们来分析一下这段代码的调用流程。
当关闭函数被调用时,在其操作范围内会影响哪些SOCK_STREAM套接字?每当一个SOCK_STREAM套接字被打开且已成功连接后,在执行关闭操作前,请注意该套接字会被重置。然而,在某些情况下(例如当调用closesocket()函数完成关闭操作后),即使存在尚未发送的数据内容,在这些情况下仍会保留这些数据。此外,在实际运行过程中,请确保每次调用WSAStartuo()函数之前都确认当前版本设置的一致性,并避免因版本不兼容导致的功能异常。
2、异步请求服务
Windows Sockets 不仅继承自 Berkeley Sockets 的同步接口,在网络通信领域还新增了一组用于执行异步操作的函数集合。作为阻塞型接口的非阻塞式增强版,WSAAsyncGerXByY() 函数能够实现无阻塞式的网络数据传输功能。当应用程序发起相关请求时,Windows Sockets 的DLL负责初始化这一操作并反馈给调用者,该功能返回一个独立于主线程的事件句柄,用于跟踪和管理这个操作进程。如果结果被保存到调用者的缓冲区中,并且会触发应用程序相应窗口的消息显示。
需要注意的地方在于,在Windows系统中内存对象是可以被指定为可移动和可丢弃的对象。I must ensure that I when performing operations on memory objects must ensure that the Windows Sockets DLL is available.
3、异步数据传输
通过 send() 或 sendto() 函数进行数据发送以及 recv() 或 recvfrom() 进行数据接收。Windows Sockets 建议避免采用阻塞方式以防止整体环境被阻塞。以下是一个异步数据传输的具体实现:
假设套接字 s 在连接建立后已注册网络事件 FD_READ 和 FD_WRITE 并且指定 wMsg 为 UM_SOCK 则可在 Windows 消息循环中添加相应的分支语句。
4、出错处理
Windows 包含一个名为 WSAGetLastError() 的函数用于检索最近的错误码。以下是编写代码时应遵循的最佳实践:使用此函数时,请确保捕获调用者的上下文状态,并按照标准错误处理流程进行响应。
发布于 [2006年4月25日 上午13:12] 的《不会飞的鸟》被阅读次数:136次 | 评论数量:O条。您可以在此处进行修改后校对或加入个人收藏夹。
本文深入探讨了Windows Socket网络编程技术的实现机制与实践应用。通过详细阐述不同套接字族的特点及其适用场景,帮助读者更好地理解其核心原理并掌握实际操作方法。其中,本文重点分析了基于Windows Socket框架的可靠数据传输机制,包括套接字族的选择标准、连接建立过程以及数据报文传输策略等关键环节的技术细节与优化方案。
通过实例剖析,本文展示了如何根据具体应用需求合理选择适合的数据传输协议,并结合窗口机制实现高效的通信过程控制。此外,文章还深入探讨了面向多线程环境下的socket对象管理方法,提出了基于事件驱动模型的socket资源调度策略,以确保系统运行效率与稳定性得到显著提升。
作为网络通信协议体系的重要组成部分之一,Sockets技术在现代分布式系统构建中发挥着不可或缺的作用。本文不仅系统梳理了Sockets核心组件的设计理念与实现细节,还结合实际案例展示了其在实际开发中的应用价值与局限性分析方法,为读者提供了全面的技术参考与实践指导建议。
一、客户机/服务器模式
在TCP/IP网络中,两个进程间的主机之间的交互模式即为客户机/服务器模式(Client/Server model).该模式基于以下两个关键点建立:一是非对称性作用;二是通信过程是异步进行的.该模式通过主动请示的方式实现了各环节之间的协调与协作.
首先由服务器启动并响应相关服务(过程如下):
- 建立通信通道后通知本地主机准备接收客户端请求。
- 当客户端请求到达指定端口时开始处理。
- 持续响应多个服务请求并发送应答信号。
- 循环处理以等待下一个客户端请求。
- 完成所有操作后关闭通信渠道。
客户端: - 建立通信通道后连接至目标主机的固定端口。
- 发送服务请求数组后持续接收回应;完成当前操作可继续提交新请求数组。
- 完成所有操作后关闭通信渠道并退出系统。

为了便于阐述套接字编程的基本原理,在此介绍几个基础型套接字。后续文章将对这些套接字的详细应用进行深入讲解。第一部分介绍的是创建新套接字的关键函数——socket()。具体格式如下所示:SOCKET PASCAL FAR socket(int af, int type, int protocol);其中af参数表示通信发生在网络层以上还是以下的位置?type参数决定了要建立哪种类型的本地连接?procotol参数指定所使用的通信协议类型?
指定本地地址——bind()
功能:通过绑定操作将套接字地址与创建的套接字号相关联。
格式:int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen);
参数:
s: 是由socket()函数返回的一个未连接的套接字描述符(表示所创建的套接号)。
其它:
若操作成功,则返回值为0;
若出现错误,则返回SOCKET_ERROR。
地址结构说明:
struct sockaddr_in {
short sin_family; // AF_INET
u_short sin_port; // 16位端口号(网络字节顺序)
struct in_addr sin_addr; // 32位IP地址(网络字节顺序)
char sin_zero[8]; // 存放零长度,默认为空字符串
};
通过调用connect()和accept()函数来实现套接字连接。功能:负责建立与指定服务器的通信。格式:int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR *name, int namelen); SOCKET PASCAL_FAR accept(SOCKET s, struct sockaddr_FAR *name, int_FAR * addrlen); 参数如下:
4、监听连接——listen()
功能:用于向服务器发送一个连接请求,并允许最多backlog个客户端同时建立连接。
实现原理:listen() 函数会在指定地址和端口上建立一个 listening 值,并返回该地址对应的套接字编号s以及最大允许并发连入的客户端数目backlog。
5、数据传输——send()与recv()
功能描述:用于实现发送和接收数据
Pascal_far Send(int Socket s, char* buf, int len, int flags);
Pascal_far Recv(int Socket s, char* buf, int len, int flags);
buf为指向存储待传输数据缓冲区的指针。
6、多路复用——select()
功能:用于检测单个或多个套接字的状态。
定义:int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,
fd_set FAR * exceptfds,const struct timeval FAR * timeout);
参数:readfds为指向需进行读检测的指针;
writefds为指向需进行写检测的指针;
exceptfs用于检测是否发生错误;
timeout表示最大等待时间。
7、关闭指定套接字——closesocket()
功能:实现指定套接字的关闭
格式:BOOL PASCAL FAR closesocket(SOCKET s);

三、典型过程图
2.1 面向连接的套接字的系统调用时序图

2 无连接协议的套接字调用时序图

3 面向连接的应用程序流程图

发布于 [2006年4月25日 上午13:11] 不飞的鸟 被访问了131次 | 没有评论 现已修改 | 收藏夹中
Windows Socket网络编程(一)——TCP/IP体系结构的特点及相关术语
**一、TCP/IP 体系结构与特点
1、TCP/IP体系结构**
位于物理网上的TCP/IP协议组成了一个完整的网络协议系统。其中TCP负责传输层功能,IP则管理网络层事务。包含以下协议的具体内容请参见图1.1
位于物理网上的TCP/IP协议组成了一个完整的网络协议系统。其中TCP负责传输层功能,IP则管理网络层事务。包含以下具体协议的内容请参考图1.1

(图1.1)
IP:互联网协议(Internet Protocol) 负责在网间传输数据并存储在网络上的内容。同时支持ICMP、TCP和UDP协议进行分组发送。
ARP:地址解析协议(Address Resolution Protocol) 将网络地址映射至对应的硬件设备接口地址。
RARP:反向地址解析协议(Reverse Address Resolution Protocol) 根据硬件设备的实际连接IP地址来反向解析出正确的网络地址。
ICMP:互联网控制消息协议(Internet Control Message Protocol) 负责处理信息传递过程中的错误报告以及通信控制问题。
TCP:传送控制协议(Transmission Control Protocol) 通过建立虚拟通道实现可靠的数据传输,并对传输过程中的错误进行检测与重传机制。
UDP:用户数据报协议(User Datagram Protocol) 仅用于直接发送数据包给接收方,并不保证传输过程中的可靠性。
FTP:文件传输协议(File Transfer Protocol) 支持用户通过类似文件操作功能(如上传下载修改查看等)实现远程主机间的通信。
SMTP:简单邮件传送 protocol(Simple Mail Transfer Protocol) 专门用于邮件系统之间的消息传递过程。
TELNET:终端protocol(Telnet Terminal Procotol) 提供了一种基于虚拟终端界面的方式让用户访问远端服务器。
HTTP:超文本传输 protocol(Hypertext Transfer Procotol)
TFTP: 简单文件传输 protocol(Trivial File Transfer Protocol)
2、TCP/IP特点
传输层协议(TCP/UDP)、网络层协议(IP)以及物理接口层共同构成了TCP/IP协议的核心体系。这些核心组件通常由操作系统内核完成功能部署,并非普通用户直接操作管理。在编程过程中:
一是在内核中直接提供的系统调用;
二是通过库函数实现的各种功能。“前者属于核内实现”,而后者则是属于“核外实现”。基于此特性,在设计应用程序时必须使用套接字(socket)来完成相关功能。“
图1.2展示了TCP/IP核心体系与应用程序之间的关系架构。”

(图1.2)
**

二、专用术语**
1、套接字
它是网络的基本构件。它是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连听进程。套接字存在通信区域(通信区域又称地址簇)中。套接字只与同一区域中的套接字交换数据(跨区域时,需要执行某和转换进程才能实现)。WINDOWS 中的套接字只支持一个域——网际域。套接字具有类型。
WINDOWS SOCKET 1.1 版本支持两种套接字:流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)
2、Windows Sockets实现
一个Windows Sockets实现是指遵循Windows Sockets规范所描述的所有功能的一套软件。通常以DLL文件的形式实现。
3、阻塞处理例程
阻塞处理程序(hook for blocking)是Windows Sockets API设计用来实现支持阻塞套接字函数调用的一种机制。
多址广播(multicast)是其本质是一种一对多的通信模式。
其核心特征在于:信息得以在单次传输中送达一组接收者。
此功能与单点传送(unicast)及传统广播(Broadcast)相呼应。
