热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

windows网络编程学习WinsockAPI

winsockwinsock是WIN32平台上提供的网络编程接口且与具体的网络协议无关(也就是说支持多种网络协议),它借鉴了Unix平台上
winsock
winsock是WIN32平台上提供的网络编程接口且与具体的网络协议无关(也就是说支持多种网络协议),它借鉴了Unix平台上的Berkeley(BSD)套接字方案(Unix socket 编程和 Winsock 编程是很相似的)。虽然winsock与协议无关,但是在编程时我们还是要了解一下网络协议的一些特征,例如:面向消息、面向连接与无连接、路由选择等。
面向消息
 这里根据网络协议的不同,可以将他们分为有消息边界和无消息边界保护的,通常把无消息边界保护的协议称为“基于流的协议”。假设发送端发出数条不同大小的消息如:128字节、256字节,而接受端将会两次进行读取每次读取一个消息的数据包,即使这些数据包已经全部搜到并存于网络堆栈中也是如此。我们熟悉的UDP协议发送的数据包,就是有消息边界保护的(同样IP的数据报也是如此)。如果是在基于流的协议里,由于消息没有保护边界,系统可能将大的消息分割或者将小的组合然后尽可能返回更多的数据。我们熟知的TCP协议就是基于流的。
面向连接或无连接
  一个面向连接的协议在数据交换之前会建立一个虚拟的路径,而且面向连接的协议通常还提供一定的可靠性保障服务(代价是维护连接需要开销)。无连接的协议只负责把数据直接投递出去其他就不关了,比较像邮政的信件寄送,虽然缺乏可靠性但是其速度快。总所周知tcp协议是面向连接的,而UDP则是无连接协议。可以根据不同的场景和需求选择使用哪种协议进行通讯。
路由
  路由器会将受到的非路由协议数据包全部丢掉(例如:NETBEUI协议)。如果我们设计的程序存在不同的网络(当然这些网络经由路由器连接着)我们就需要选择可路由的协议,首推的当然是TCP/IP了。
WSAStartup 函数
在使用winsock编程前需要先加载winSock库,也就是调用WSAStartup函数(这是与Unix socket的最主要区别)。int WSAStartup(WORD wVersionRequested , LPWSADATA lpWSAData),该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节 指明副版本、低位字节指明主版本(可以利用宏MAKEWODE(2,0)获得 wVersionRequested);操作系统利用第二个参数返回请求的Socket的版本信息(有用的只有 wVersion和wHighVersion 这两个而已)。当一个应用程序调用WSAStartup函数时,操作系统根 据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的 其它Socket函数了,该函数执行成功后返回0。

1 wVersionRequested = MAKEWORD( 2, 2 );
2 err = WSAStartup( wVersionRequested, &wsaData );
我们来看看在.NET C#语言下是怎么调用WSAStartup函数的,当然我们在使用C#是不需要显示打开winsock库,.net帮我们封装好了。用Reflector找到System.Net.Socket类(我的是.net3.5)。查看public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) 在里面发现了这么两句话:

1 InitializeSockets();
2 this.m_Handle = SafeCloseSocket.CreateWSASocket(addressFamily, socketType, protocolType);
3  
 其中.m_Handle是一个SafeCloseSocket类(其实祖先是 SafeHandle 类,另附:安全句柄和紧急终结),再看看InitializeSockets()方法发现了如下语句:

if (UnsafeNclNativeMethods.OSSOCK.WSAStartup(0x202, out lpWSAData) != SocketError.Success)
{
throw new SocketException();
}
继续跟踪就可以发现:

[DllImport("ws2_32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
internal static extern SocketError WSAStartup([In] short wVersionRequested, out WSAData lpWSAData);
其中ws2_32.dll便是Windows Sockets应用程序接口的动态链接库文件,用DllImport的方式就可以使用这个WIN32 api了。所以当我们使用Socket类生产一个Socket实例时系统便会帮我们调用WSAStartup。
WSACleanup
每次调用了WSAStartup都需要调用WSACleanup来释放资源。
WSAEnumProtocols函数
如果想知道系统里安装了哪些协议和这些协议的特性,可以调用int WSAEnumProtocols(lpdwProtocols,lpProtocolBuffer,lpdwBufferLength),通常需要两次调用WSAEnumProtocols()函数以获取特定的协议信息,第一次调用时指定lpdwProtocols为 NULL,调用肯定是失败的,但参数lpdwBufferLength包含了所有协议信息需要的缓冲区长度。我们知道了这个准确长度就可以进行第二次调用了。
WSASocket
winsock API 是建立在套接字上的,套接字其实就是一个句柄(C#层面上我们可看作是一个抽象的对象)。SOCKET WSASocket(int af,int type,int protocols,LPWSAProtocol_INFO lpprotocolInfo,GROUP g,DOWRD dwFlags) 使用这个函数我们就可以创建套接字了
  • af:地址族描述。如果想建立UDP或TCP的套接字,可以使用 AF_INET来指定互联网协议
  • type:新套接口的类型描述。它可以是:SOCKSTREAM、SOCKDGRAM、SOCKSEQPACKET、SOCKRAW和SOCKRDM。
  • protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0,需要注意的是protocol 和 type是由一定对应关系的
  • lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。
  • g:套接口组的描述字。
  • iFlags:套接口属性描述。
还记得在.NET C#语言下是怎么调用WSAStartup函数的吗? 在 SafeCloseSocket 里找到了InnerSafeCloseSocket类

internal class InnerSafeCloseSocket : SafeHandleMinusOneIsInvalid
{
// Fields
private bool m_Blockable;
private static readonly byte[] tempBuffer;

// Methods
static InnerSafeCloseSocket();
protected InnerSafeCloseSocket();
internal static SafeCloseSocket.InnerSafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressSize);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal void BlockingRelease();
internal static unsafe SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket(byte* pinnedBuffer);
internal static SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType);
protected override bool ReleaseHandle();

// Properties
public override bool IsInvalid { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get; }
}
我们看看 SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket() 方法是如何实现的:

internal static SafeCloseSocket.InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
SafeCloseSocket.InnerSafeCloseSocket socket
= UnsafeNclNativeMethods.OSSOCK.WSASocket(addressFamily, socketType, protocolType, IntPtr.Zero, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
if (socket.IsInvalid)
{
socket.SetHandleAsInvalid();
}
return socket;
}
可看到在OSSock 类里有以下引用:
ContractedBlock.gifExpandedBlockStart.gif代码

[DllImport("ws2_32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern SafeCloseSocket.InnerSafeCloseSocket WSASocket([In] AddressFamily addressFamily, [In] SocketType socketType, [In] ProtocolType protocolType, [In] IntPtr protocolInfo, [In] uint group, [In] SocketConstructorFlags flags);



 

不过令我意外的是 这个OSSOCKET 竟然是在UnsafeNclNativeMethods 下的,这个难道是不安全的吗? 能找到的UnsafeNclNativeMethods的资料不多(哪位大牛知道希望指点指点),我对.net的 GC机制也只是知道其意思,而不知道其具体是怎么实现的。

转:https://www.cnblogs.com/keyindex/archive/2010/12/17/1908405.html



推荐阅读
  • python3+tkinter实践历程(四)——模仿CRT完成基于socket通信与tkinter的TCP串口客户端
    python3tkinter实践历程(四)——基于socket通信与tkinter的TCP串口客户端(仿CRT)文章目录系列文章目录分享背景制作背景最终功能工具截图展示代码详解系列 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 如何使用PLEX播放组播、抓取信号源以及设置路由器
    本文介绍了如何使用PLEX播放组播、抓取信号源以及设置路由器。通过使用xTeve软件和M3U源,用户可以在PLEX上实现直播功能,并且可以自动匹配EPG信息和定时录制节目。同时,本文还提供了从华为itv盒子提取组播地址的方法以及如何在ASUS固件路由器上设置IPTV。在使用PLEX之前,建议先使用VLC测试是否可以正常播放UDPXY转发的iptv流。最后,本文还介绍了docker版xTeve的设置方法。 ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • 转自:微点阅读(www.weidianyuedu.com)微点阅读-范文大全-免费学习知识的网站电脑唯独搜不到自己家wifi,别人家的都能搜到,手机也可以搜到自己家的,就是电脑不可 ... [详细]
  • pc电脑如何投屏到电视?DLNA主要步骤通过DLNA连接,使用WindowsMediaPlayer的流媒体播放举例:电脑和电视机都是连接的 ... [详细]
  • AstridDAO 专访:波卡稳定币黑马 BAI
    加入Pol ... [详细]
  • 这篇文章给大家讲解如何利用dhtmlxGantt在服务器端集成数据。脚本数据保存如果您已初始化dataProcessor,则用户或以编程方式所做的任何更改都将自动 ... [详细]
author-avatar
mR_woManh
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有