介绍利用套接字编程时需要的一些函数。

1.  WSAStartup 函数

利用套接字编程时,第一步需要加载套接字库,通过 WSAStartup 函数来实现。

该函数有两个功能:

  1. 加载套接字库
  2. 进行套接字库的版本协商——确定使用的Socket版本

函数原型如下:

两个参数含义如下:

  1. wVersionRequested :用来指定准备加载的Winsock库的版本。因为是一个双字,一般高位字节为WinSock的副版本号,低位字节为主版本号。通常版本号为2.1,则2是主版本号,1是副版本号。可以使用 MAKEWORD(x,y) 宏方便获得 wVersionRequested 的值。(x是高位字节,y是低位字节)
  2. lpWSAData :一个返回值,指向WSADATA结构的指针。WSAStartup 函数用其加载的库版本有关的信息填在这个结构中。

WSADATA的结构定义如下:

WSAData 参数解析:

  1. wVersion :目前使用的Winsock版本。
  2. wHighVersion : 这个DLL能够支持的Windows Sockets规范的最高版本。
  3. iMaxSockets : 单个进程能够打开的socket的最大数目。
  4. iMaxUdpDg : Windows Sockets应用程序能够发送或接收的最大的用户数据包协议(UDP)的数据包大小,以字节为单位。如果实现方式没有限制,那么iMaxUdpDg为零。
  5. lpVendorInfo : 指向销售商的数据结构的指针。这个结构的定义(如果有)超出了WindowsSockets规范的范围。WinSock2.0版中已被废弃
  6. szDescription : 以null结尾的ASCII字符串,Windows Sockets DLL将对Windows Sockets实现的描述拷贝到这个字符串中,包括制造商标识。
  7. szSystemStatus : 以null结尾的ASCII字符串,Windows Sockets DLL把有关的状态或配置信息拷贝到该字符串中。

对于每一个 WSAStartup 函数的成功调用(成功加载WinSock动态库),在最后都对应一个WSACleanUp调用,以便释放为该应用程序分配的资源,终止对WinSock动态库的使用。

 

 

2.  socket 函数

加载了套接字库后,就可以调用socket函数创建套接字,函数原型声明如下:截取自:<Winsock2.h>

看着稍乱,可以理解为:

socket函数接受三个参数:

  1. af 指定地址族,对于TCP/IP协议的套接字,它只能是 AF_INET 或者 PF_INET ;
  2. type 指定 Socket 类型,对于1.1版本的Socket只支持两种类型的套接字:SOCK_STREAM(流式套接字) 和 SOCK_DGRAM(数据报套接字)。
  3. protocol 是与特定的地址家族相关的协议,如果指定为0,那么系统就会根据地址格式和套接字类别,自动选择一个合适的协议。

如果socket调用成功,就会返回一个新的 SOCKET 数据类型的套接字描述符。

如果socket调用失败,就会返回一个 INVALID_SOCKET 值,错误信息可以通过 WSAGetLastError 函数返回。

 

这里详细讲述下socket相关的参数,可以当做了解

以下代码大多来自: <Winsock2.h> 和 <ws2def.h>

socket的版本应该是2.2版本:

af 的值列表及解释:很多都很难找到…望留言可修改…

Windows下的AF对应的PF:

type的值:

 

protocol的值:protocol用来指定socket所使用的传输协议编号,通常此参考不用管它,设为0即可。

大致就是以上这些。

 

3. bind 函数

创建了套接字后,应将该套接字绑定到本地的某个地址和端口上,这需要通过 bind 函数实现。

稍长,可以理解为:

bind函数接受三个参数:

  1.  s 指定要绑定的套接字。
  2.  name 制定了该套接字的本地地址信息。
  3.  namelen 很明显是name的长度。

bind的函数调用成功,则返回0,如果调用失败,则返回一个 SOCKET_ERROR,错误信息通过 WSAGetLastError 函数返回。

这里要讲的是 name 即 sockaddr 的结构:

sockaddr 的结构有两个字段:

  1. 第一个字段(sa_family) 指定地址家族,对于 TCP/IP 类型的套接字,必须指定为 AF_INET .
  2. 第二个字段(sa_data)仅仅是表示要求一块内存分配区,起到占位的作用,该区域指定与协议相关的具体地址信息。

对于不同的协议家族,使用不同的结构来替换 sockaddr。除了 sa_family 之外,sockaddr 是按网络字节顺序表示的。

在基于 TCP/IP 的socket编程中,可以用 sockaddr_in 结构替换 sockaddr,以方便我们填写地址信息。

sockaddr_in 的成员:

  1.  sin_family 表示地址族,对于IP地址,一直是 AF_INET
  2.  sin_port 表示分配给套接字的端口号
  3.  sin_addr 给出的是套接字的主机IP地址
  4.  sin_zero 只是一个填充数,以使 sockaddr_in 和 sockaddr 长度相同。

另外 sin_addr 成员的类型是 in_addr 其类型是: <inaddr.h>

可以看到这是一个union,共用体的结构

通常用这个结构将一个点分十进制的ip地址转换为u_long 类型,并将结果赋给 S_addr 。

 

4. inet_addr 和 inet_ntoa 函数

将IP地址指定为 INADDR_ANY ,允许套接字向任何分配给 本地机器的 IP 地址 发送或接受数据。

INADDR_ANY  在<Winsock2.h> 文件中有定义:

啥意思呢,就是多数情况下,每一个机器只有一个IP,但有的机器可能会有多个网卡, 每个网卡都有自己的IP地址,用 INADDR_ANY 可以简化应用程序的编写,即我所有的网卡都可以侦听或者发送数据。

当然如果我们只想让套接字(socket)使用多个ip中的一个地址,就必须使用实际的地址。

要做到这一点,可以使用 inet_addr 函数来实现。原型如下:

简化版就是这样的:

一个字符串作为其参数,该字符串指定了以点分十进制格式表示的IP地址 (如:192.168.1.1)

而且 inet_addr 函数 会返回一个适合分配给 S_addr 的 u_long 类型的数据。(参考前面的 bind )

inet_ntoa 函数会完成相反的转换,它接受一个 in_addr 结构体类型作为参数,并会返回一个点分十进制格式表示的IP地址字符串

函数原型如下:

简化版是这样样子的:

 

5. listen 函数

该函数作用是将指定的套接字设置为监听模式…函数原型如下:<Winsock2.h>

简化版就是这样的:

两个参数:

  1. 第一个参数 s套接字描述符 。
  2. 第二个参数 backlog 是 等待队列的最大长度 ,如果设置为 SOMAXCONN ,那么下层的服务提供者将这个套接字设置为最大的合理值。

一个返回值:

无错误发生,返回0。

有错误发生,返回-1,可通过 WSAGetLastError() 获取错误代码。

注意点:

  1. listen 函数 仅适用于支持连接的套接口,如SOCK_STREAM类型的。
  2. backlog 参数 是等待队列的最大长度而不是一个端口上同时连接的数目。例如:backlog设置为2,如果有三个请求到来,前两个放入等待请求连接队列中,应用程序依次处理这些请求服务,第三个请求则被拒绝。

 

6. accept 函数

该函数是接受客户端发送的连接请求。函数原型如下:

简化版如下:

有三个参数,返回一个和客户端通信的Socket

  1. 第一个参数 s 是套接字描述符
  2. 第二个参数 addr 是指向一个缓冲区的指针,该缓冲区接受连接实体的地址,也就是当客户端向服务端发起连接,服务端接受这个连接时,保存发起连接的这个客户端的Ip地址信息和端口信息
  3. 第三个参数 addrlen 也是一个返回值,整型指针,包含地址信息的长度

 

7. send 函数

通过已建立连接的套接字发送数据。函数原型如下:

简化版如下:

四个参数:

  1. 第一个参数 s 是已建立连接的套接字。
  2. 第二个参数 buf 指向一个缓冲区,该缓冲区包含将要传递的数据
  3. 第三个参数 len缓冲区的长度
  4. 第四个参数 flags 设定的值将影响函数的行为,一般设置为0即可。

返回值:

如果无错误,返回值为所发送数据的总数。

如果有错误,返回SOCKET_ERROR。

 

8. recv 函数

从一个已连接的套接字接受数据。函数原型如下:

简化版如下:

四个参数:

  1. 第一个参数 s 是接受数据的套接字。
  2. 第二个参数 buf 是指向缓冲区的指针,用来保存接收的数据
  3. 第三个参数 len 是缓冲区长度
  4. 第四个参数 flags 设定会影响函数的行为。

返回值:

recv函数返回其实际copy的字节数。

如果在copy时出错,那么它返回SOCKET_ERROR;

如果在等待协议接收数据时网络中断了,那么它返回0。

 

9.connect 函数

该函数的作用是与一个特定的套接字建立连接。函数原型如下:

简化后如下:

三个参数:

  1. 第一个参数 s 是即将在其上建立连接的套接字
  2. 第二个参数 name 设定连接的服务器端地址信息
  3. 第三个参数 namelen 指定服务端地址长度

返回值:

成功则返回0,失败返回非0.

 

10.recvfrom 函数

该函数接受一个数据报信息并保存源地址。原型声明如下:

简化后如下:

六个参数:

  1. 第一个参数 s 是准备接受数据的套接字。
  2. 第二个参数 buf 是一个指向缓冲区的指针。
  3. 第三个参数 len 是缓冲区的长度。
  4. 第四个参数 flags 的值会影响函数行为。
  5. 第五个参数 from 是一个指向地址结构的指针,主要是用来接受发送方的地址信息。
  6. 第六个参数 fromlen 是一个整型指针,并且它是一个 in/out 类型的参数,表明在调用前需要给它指定一个初始值,函数调用过后,会通过这个参数返回一个值,该返回值是地址结构的大小。

UDP使用recvfrom()函数接收数据,成功则返回接收到的字符数,失败返回-1。

 

11. sendto 函数

向一个特定的目标发送数据。函数原型如下:

简化后如下:

六个参数:

  1. 第一个参数 s 是一个套接字描述符。
  2. 第二个参数 buf 是一个指向缓冲区的指针,包含要发送的数据。
  3. 第三个参数 len 是缓冲区中数据长度。
  4. 第四个参数 flags 的设置会影响函数调用行为。
  5. 第五个参数 to 是一个可选的指针,指定目标套接字地址。
  6. 第六个参数 tolen 是指定地址的长度。

UDP用sendto()函数发送数据,如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。

 

12. htons 和 htonl 函数

htons 把一个 u_short 类型的值从主机字节顺序转换为 TCP/IP 网络字节顺序。

htonl  把一个 u_long  类型的值从主机字节顺序转换为 TCP/IP 网络字节顺序。

两个函数原型如下:

简化后如下所示:

 

相关链接:

TCP应用程序:

  1. 服务端:http://blog.tk-xiong.com/archives/586
  2. 客户端:http://blog.tk-xiong.com/archives/588

 

完~

【Socket】套接字编程相关函数
Tagged on:
0 0 投票数
Article Rating
订阅评论
提醒

0 评论
内联反馈
查看所有评论