Windows 套接字编程


一、常见概念

1、Windows Sockets 规范

  • Windows Sockets 规范是 Windows 平台下定义的可以兼容二进制数据传输的网络编程接口,是基于伯克利加利福尼亚大学的 BSD UNIX Sockets 的实现;规范包括 BSD 格式的 Sockets 函数和 Windows 拓展函数。
  • 使用 Windows Sockets 的应用程序可以与任何兼容 Windows Sockets API 的网络程序进行通信。

2、套接字及其分类

  • 在 Windows Sockets 规范中,使用套接字(socket)代表通信端点,在网络上通过 Windows Sockets 应用程序发送或接收数据包的对象。
  • Socket 具有类型和名称,并具有与其类型相关的运行过程;目前,socket 使用 IP 与其他 socket 进行双向数据交换。
  • Socket 套接字分为两种类型:数据报 socket 和数据流 socket。

2.1、数据报套接字

  • 数据报套接字,即无连接套接字,是不需要连接即可进行通信的套接字,可以向指定的 socket 发送数据报消息,也可以从指定的 socket 接收消息;但不保证传输的可靠性,即通过数据报套接字传输的数据在到达目的端时,可能出现字节顺序被打乱的情况。
  • 数据报套接字的一个典型应用就是,保持系统时间与网络同步。

2.2、数据流套接字

  • 数据流套接字是基于显示连接的套接字,提供没有记录边界的双向字节数据流,具有可靠的发送顺序,适用大量数据且可靠性要求高的传输。

  • 客户端 socket 请求到服务器 socket,服务器 socket 可以接收连接请求,也可以拒绝连接请求。

  • 数据流套接字的典型应用有电话呼叫和 FTP(File Transfer Protocol,文件传输协议)

  • 在一些网络层协议下,如 XNS,数据流是面向记录的数据流,而不是字节流。而在更通用的 TCP/IP 协议下,数据流是面向字节的字节流。

  • Windows Sockets 提供独立于底层协议的抽象层。

3、客户端/服务器(C/S)模型

  • 客户端/服务器模型是常见的一种架构模型,将应用程序分为前端客户端组件和后台服务器组件。客户端组件运行在工作站中,负责从用户处接收数据,为服务器处理数据,并形成到服务器的连接;后台服务器等待客户端的连接,当服务器接收到客户端的连接请求后,服务器会处理并返回给客户端响应信息;客户端接收到响应消息,通过用户接口呈现给用户。

  • 在设计基于客户端/服务器模型的应用程序时,程序的性能和可拓展性是设计的关键要素;还需要考虑程序的组件和基本处理,包括数据包设计、物理部署模型、远程服务器负载以及网络带宽的分析等问题。

  • 影响客户端/服务器模型正常运行有以下因素:

    1)服务器平台硬件问题

    2)服务器平台软件问题

    3)网络问题

    4)应用程序问题

4、网络字节顺序

  • 不同机器采用不同的字节顺序存储数据,如基于 Intel 处理器的机器与 Macintosh(Motorola)机器存储数据的字节顺序是相反的。Intel 采用的字节顺序称为“小头方式”,即低字节在前,高字节在后的方式;而标准的网络顺序是“大头方式”,即高字节在前,低字节在后的方式。两种方式表示如下:

    将 0x123456789 写入到以 0x0000 开始的内存中,则结果为:大头方式   小头方式0x0000       0x12       0x340x0001       0x34       0x120x0002       0x56       0x780x0003       0x78       0x56
    
  • 一般情况下,用户不需要处理网络上发送和接收数据的字节顺序的转换,但下面几种情况,需要用户手动转换字节顺序:

    1)用户传输的信息需要网络解释

    2)当与之通信的服务器应用程序不是 MFC 应用程序

  • 下面几种情况,不需要用户调用字节转换

    1)两台机器使用相同的字节顺序,并且两端约定不进行字节交换

    2)与之通信的服务器是 MFC 应用程序

    3)用户有与之通信的服务器的源代码,因此可以显式地说明是否转换字节顺序

    4)可以将服务器转换为 MFC 程序

  • Windows Sockets 提供了 4 个转换函数,如下表:

    函数 功能
    ntohs() 将 16 位数从网络字节顺序转换成主机字节顺序,即从“大头方式”转换为“小头方式”
    ntohl() 将 32 位数从网络字节顺序转换为主机字节顺序,即从“大头方式”转换为“小头方式”
    htons() 将 16 位数从主机字节顺序转换成网络字节顺序,即从“小头方式”转换为“大头方式”
    htonl() 将 32 位数从主机字节顺序转换成网络字节顺序,即从“小头方式”转换为“大头方式”
  • 下面使用存档的 CSocket 对象的序列化函数为例,说明如何使用字节转换顺序;假定参与编写的程序通信的是非 MFC 服务器应用程序,并且没有源代码,使用的是标准的网络字节顺序。协议通信包为:

    struct MyPack
    {long Number; // 流水号unsigned short Command; // 命令标识short ParamA; // 参数Ashort ParamB; // 参数B
    }
    
  • 在 MFC 中其定义为:

    struct MyPack
    {long m_lMagicNumber; // 流水号unsigned short m_nCommand; // 命令标识short m_nParamA; // 参数Ashort m_lParamB; // 参数Bvoid Serialize(CArchive& ar); // 序列化函数。
    }
    
  • Serialize(CArchive& ar) 的定义为:

    void MyPack::Serialize(CArchive& ar)
    {if(ar.IsStoring())  // 如果是存储对象{ar<<(DWORD)htonl(m_lMagicNumber); // 存储流水号为 DWORDar<<(WORD)htons(m_nCommand);  // 存储命令标识为 WORDar<<(WORD)htons(m_nParamA);  // 存储参数A为 WORDar<<(WORD)htonl(m_lParamB)   // 存储参数B为 WORD}else  // 如果是提取对象{WORD w;  // 定义 WORD 变量DWORD dw;  //  定义 DWORD 变量ar>>dw;  // 提取 DWORD 值m_lMagicNumber = ntohl((long)dw);  // 将提取的 DWORD 值转换为流水号ar>>w;  // 提取 WORD 值m_nCommand = ntohs((short)w); //  转换为命令标识符ar>>w;m_nParamA = ntohs((short)w); // 转化为参数Aar>>w;m_lParamB = ntohl((short)w); // 转换为参数B}
    }
    

二、套接字库函数

  • Windows Socket 规范定义了一组套接字函数,用于完成 Socket 编程,还定义了一组用于处理域名、通信协议等数据的数据库函数;同时,为了与 Windows 编程模型一致,微软还提供了一组拓展的 Socket 函数。

1、套接字函数

  • Windows Sockets 规范中的套接字函数,如下表:

    套接字函数 功能
    accept() 当有客户端 socket 连接到服务器 socket 时,服务器用此函数接收客户端的连接,此函数的返回值为新建的 socket,维护与客户端 socket 之间的通信,服务器可以维护多个客户端的 Socket 连接。此函数仅对面向连接的套接字有效。
    bind() 服务器 Socket 使用此函数绑定到本地指定端口,当指定端口有连接到来时,可以通知服务器 Socket,再由其决定接受(accept)socket 的连接还是拒绝。
    closesocket() 关闭 socket。对于没有设置超时时间的阻塞 socket,此函数仅仅阻塞 socket 通信
    connect() 在指定 socket 上初始化连接,客户端 socket 使用此函数连接到服务器 socket
    getpeername() 获取指定 socket 连接对端的名称
    getsocketname() 获取 socket 绑定的本地地址
    getsocketopt() 获取与指定 socket 相连的选项
    htonl() 将 32 位整数从主机字节顺序转换成网络字节顺序
    htons() 将 64 位整数从主机字节顺序转换成网络字节顺序
    inet_addr() 将使用点号分隔的 IP 地址转换成 Internet 地址值
    inet_ntoa() 将 Internet 地址值转换成使用点号分隔的 IP 地址
    ioctlsocket() 提供 socket 控制
    listen() 服务器 socket 调用此函数启动监听,开始监听是否有客户端 socket 连接
    ntohl() 将 32 位整数从网络字节顺序转换成主机字节顺序
    ntohs() 将 64 位整数从网络字节顺序转换成主机字节顺序
    recv() 从无连接的或面向连接的 socket 接收数据
    recvfrom() 从无连接的 socket 处接收数据
    select() 处理多个 I/O 同步
    send() 发送数据到面向连接的 socket
    sendto() 发送数据到面向连接或无连接的 socket
    setsocketopt() 设置指定 socket选项
    shutdown() 断开 socket 的双向通信
    socket() 创建通信的 socket 对象,并返回 socket 信息

2、数据库函数

  • Windows Socket 规范中定义了一组专门用于处理域名、通信服务和通信协议等网络信息的数据库函数。使用这些函数可以获取网络能力的检测,使用 getXbyY 的函数形式,含义是通过 Y 值获取 X 值。主要包括以下 7 个函数:

(1)gethostname() 函数

  • 其原型如下:

    int gethostname(
    char FAR * name,  // 存放返回的主机名称的缓冲区的指针
    int namelen); // 存放缓冲区的长度
    
  • 此函数返回本地主机的机器名到 name 参数指定的缓冲区中,返回的主机名是以 NULL 结束的字符串。

(2)gethostbyaddr() 函数

  • 根据网络地址获取主机信息,其函数原型为:

    struct HOSTENT FAR * gethostbyaddr(const char FAR * addr, // 网络字节顺序的地址指针int len,  // addr 参数的长度int type); // 指定地址的类型
    
  • 该函数返回一个 HOSTENT 结构的指针,其中包含传入的网络地址对应的名称和地址,所有数据都是以 NULL 结束;如果返回值是 NULL,则表示函数调用失败。

(3)gethostbyname() 函数

  • 从主机数据库中根据主机名获取主机信息,其函数原型:

    struct hosten FAR * gethostbyname(const char FAR * name); // 以 NULL 结束的主机名称
    
  • 该函数返回一个指向 HOSTENT 结构的指针,结构中的 name 参数中包含查询到的结果值;如果返回 NULL,则表示调用失败。

(4)getprotobyname() 函数

  • 根据协议名称获取协议信息,其原型为:

    struct PROTOENT FAR * getprotobyname(const char FAR * name); // 以 NULL 结束的协议名的指针
    
  • 此函数返回 name 参数指定的包含协议和协议号的 PORTOENT 结构指针;如果返回 NULL,则表示调用失败。

(5)getprotobynumber()函数

  • 根据协议号获取协议信息,其原型为:

    struct PRPTOENT FAR * getprotobynumber(int number); // 要查询的协议的主机字节顺序的协议号
    
  • 此函数返回包含协议名和协议号的 PROTOENT 指针,如果返回 NULL,则表示调用失败。

(6)getservbyname() 函数

  • 根据服务器名和协议获取服务器信息,其函数原型:

    struct SERVENT  FAR * getservbyname(const char FAR * name, // 指向服务器名称的以 NULL 结束的字符串的指针const char FAR * proto); // 指向协议名的以 NULL 结束的字符串的指针
    
  • 此函数返回包含服务器名称和服务号的 SERVENT 结构的指针,如果返回 NULL,则表示调用失败。

(7)getservbyport() 函数

  • 根据端口号和协议获取服务信息,其函数原型:

    struct SERVENT FAR * getservbyport(int port, // 指定网络字节顺序的服务的端口const char FAR * proto) // 协议名指针
    
  • 此函数返回包含服务器名称和服务号的 SERVENT 结构的指针,如果返回 NULL,则表示调用失败。

3、Windows 拓展函数

  • Windows Socket 规范提供了一组基于 berkeley 套接字的拓展函数,在实现 Socket 功能的基础上,还允许基于消息或函数进行处理,处理异步网络事件,开启重叠 I/O 功能。

  • 具体如下:

    Windows 拓展函数 功能
    WSAAceept() accept() 函数的拓展版本,允许条件接收和 Socket 分组
    WSAAsyncGetHostByAddr() 根据地址异步获取主机,基于消息实现
    WSAAsyncGetHostByName() 根据名称异步获取主机,基于消息实现
    WSAAsyncGetProtoByname() 根据名称异步获取协议信息,基于消息实现
    WSAAsyncGetProtoByNumber() 根据协议号异步获取协议信息,基于消息实现
    WSAAsyncGetServerByName() 根据服务器名称和端口号,异步获取服务器信息,基于消息实现
    WSAAsyncGetServerByPort() 根据端口号和协议,异步获取服务器信息,基于消息实现
    WSAAsyncSelect() 实现异步版本的 select() 函数
    WSACancelAsyncRequest() 取消异步获取系列函数,即取消 WSAAsyncGetXByY() 函数
    WSACleanup() 退出底层的 Windows Socket DLL 的引用
    WSACloseEvent() 销毁事件对象
    WSAConnect() Connect() 函数的拓展版本,允许交换连接数据和 QOS 标准
    WSACreateEvent() 创建事件对象
    WSADuplicateSocket() 复制 Socket
    WSAEnumNetWorkEvents() 枚举网络事件
    WSAEnumProtocols() 枚举当前系统中每个有效的协议信息
    WSAEventSelect() 连接网络事件和时间对象
    WSAGetLastError() 获取最近的 Windows Socket 错误信息
    WSAGetOverlappedResult() 返回重叠操作的完成状态
    WSAGetQOSByName() 根据服务名获取 QOS 参数
    WSAHtonl() Htonl() 函数的拓展版本,将 32 位整数从主机字节顺序转换成网络字节顺序
    WSAHtons() Htons() 函数的拓展版本,将 64 位整数从主机字节顺序转换成网络字节顺序
    WSAIcotl() ioctl() 函数的重叠执行版本
    WSAJoinLeaf() 增加一个节点到会话中
    WSANothl() ntohl() 函数的拓展版本,将 32 位整数从网络字节顺序转换成主机字节顺序
    WSANtohs() ntohs() 函数的拓展版本,将 64 位整数从网络字节顺序转换成主机字节顺序
    WSAProviderConfigChange() 接收安装服务或者卸载服务的通知消息
    WSARecv() Recv() 函数的拓展版本
    WSARecvFrom() recvfrom() 函数的拓展版本
    WSAResetEvent() 重置事件对象
    WSASend() send() 函数的拓展版本
    WSASendTo() sendto() 函数的拓展版本
    WSASetEvent() 设置事件对象
    WSASetLastError() 设置最近的错误信息
    WSASocket() socket() 函数的拓展版本;使用 WSAPROTOCOL_INFO 结构作为输入参数,并创建重叠 socket()
    WSAStartup() 初始化 Windows Socket DLL
    WSAWaitForMultipleEvents() 在多个事件对象上阻塞

MFC—windows套接字编程相关推荐

  1. 孙鑫MFC笔记之十四--多线程同步与异步套接字编程

    线程同步有三种方式: 1.      互斥对象涉及方法: HANDLE hMutex=CreateMutex(NULL,FALSE,NULL); //第二个参数为FALSE,将互斥对象声明为空闲状态 ...

  2. Yeelink平台查询开关量——套接字编程 Windows平台

    1.前言     [2014年4月重写该博文]     曾想使用STM32+LwIP实现一个yeelink应用,但是基础知识不够所以只能耐心学习.提到LwIP自然想到socket套接字,为了降低学习难 ...

  3. Yeelink平台推送传感器结果——套接字编程 Windows平台

    1.前言     本文使用windows平台的socket套接字实现向yeelink平台推送传感器结果.     [相关博文]     [ MinGW安装和使用总结 ]     [Yeelink Ht ...

  4. Windows平台的原始套接字编程的知识点概要(备忘)

    其实从大学学习了C语言后,翻看整本教材只有C语言的语法,根本没有网络编程相关的任何内容,现在回想起来,都记不起自己何时在哪本书上学习了套接字编程,说起TCP.UDP,能知道他们的区别,相关的编程的&q ...

  5. 《Windows网络编程案例教程》-董相志 学习记录 阻塞/非阻塞套接字编程

    <Windows网络编程案例教程>-董相志 学习记录 阻塞/非阻塞套接字编程 2.3 阻塞/非阻塞套接字编程 阻塞套接字编程通信流程图 2.3.1 阻塞套接字客户机编程 1.启动并初始化W ...

  6. C# 套接字编程:Scoket,我用Scoket做的C# Windows应用程序如下:

    首先请允许我做一个截图: 以上,是我服务端设计 我们知道:服务器端口数最大可以有65535个,但是实际上常用的端口才几十个,由此可以看出未定义的端口相当多.因此,我们可以通过程序随机获取一个当前可用的 ...

  7. 套接字编程(VC_Win32)

    简介(源于维基) Berkeley套接字(也作BSD套接字应用程序接口)刚开始是4.2BSD Unix操作系统(于1983发布)的一套应用程序接口.然而,由于AT&T的专利保护着UNIX,所以 ...

  8. 1.3.1 数据报套接字编程

    1.3  实现超链接 在网络应用过程中,特别是在Web程序中,超级链接用得非常普遍.其实使用VC技术,也可以实现超级链接功能.在本节的内容中,将介绍使用Visual C++ 6.0开发一个实现超级链接 ...

  9. Linux之socket套接字编程20160704

    介绍套接字之前,我们先看一下传输层的协议TCP与UDP: TCP协议与UDP协议的区别 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UD ...

最新文章

  1. MFCC+DTW做声纹识别
  2. .net中6个重要的基础概念:Stack, heap, Value types, reference types, boxing and Unboxing.
  3. 比特币交易构成(二)
  4. svn教程----TortoiseSVN常用操作
  5. busybox 安装mysql_安装busybox
  6. android socket 长连接_TCP/IP,http,socket,长连接,短连接
  7. 计算机系统基础 计算机系统的基本组成与基本功能
  8. 4位先行进位电路 logisim_你真的了解74系列集成电路吗?让我帮你总结一下
  9. 面经 | 靠一份PPT做自我介绍,成功拿下了互联网名企offer
  10. 11月最新系统GHOST XP SP3 电脑城快速装机版 V2011.11
  11. Unity EditorWindow Rename
  12. Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entr
  13. 智能急救站入驻公共场所,搭起生命安全新防线
  14. 太原学院计算机科学与技术在哪个校区,太原学院有几个校区及校区地址
  15. 验证IBIS模型正确并转换为DML模型图文演示
  16. xshell6个人版解除窗口限制(亲测可用,需卸载当前xshell6)
  17. 程序员正确打开碎片时间的方法
  18. python分割_Python文件合并与分割操作方法工具
  19. Java编程配置思路详解,手把手教会你
  20. 3、孟子·滕文公上 孟子·滕文公下

热门文章

  1. FloatingActionButton图片居中
  2. dojo入门介绍(一)
  3. 关联挖掘算法及其应用(1)
  4. UbuntuServer搭建MQTT服务器
  5. 目前较好的私域流量运营软件有哪些?
  6. 什么是序列,Python序列详解(包括序列类型和常用操作)
  7. 【周鸿祎】给创业者的三个建议:融…
  8. Python 实用代码工具集目录
  9. 网络-ARP协议详解与ARP欺骗(中毒)攻击实战
  10. html5t制作百叶窗,【BIM免费教程】Revit制作参数化百叶窗族的过程