Windows socket C语言编程

Windows socket C语言编程函数详解

文章目录

  • Windows socket C语言编程函数详解
      • WSADATA
      • WSAStartup
      • socket
      • sockaddr
      • sockaddr_in
      • inet_pton
      • setsockopt
      • bind()
      • connect()
      • recvfrom
      • sendto()

WSADATA

用来存储被WSAStartup函数调用后返回的[Windows Sockets](https://baike.baidu.com/item/Windows Sockets)数据。它包含Winsock.dll执行的数据。

WAS(Windows Sockets Asynchronous,Windows异步套接字)

用来存储被WSAStartup函数调用后返回的Windows Sockets数据。它包含Winsock.dll执行的数据。

typedef struct WSAData {
    WORD          wVersion; //高位字节存储副版本号, 低位字节存储主版本号
    WORD          wHighVersion;//支持的Windows Sockets规范的最高版本
#ifdef _WIN64
    unsigned short     iMaxSockets;//单个进程能够打开的socket的最大数目
    unsigned  short    iMaxUdpDg;
    //能够发送或接收的最大的用户数据包协议(UDP)的数据包大小,以字节为单位
    char FAR *       lpVendorInfo;
    char          szDescription[WSADESCRIPTION_LEN+1];//WinSockets实现的描述
    char          szSystemStatus[WSASYS_STATUS_LEN+1];//有关的状态或配置信息
#else
    char         szDescription[WSADESCRIPTION_LEN+1];
    char         szSystemStatus[WSASYS_STATUS_LEN+1];
    unsigned  short     MaxSockets;
    unsigned  short     iMaxUdpDg;
    char FAR *       lpVendorInfo;
#endif
} WSADATA;

WSAStartup

int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData )

通过WSAStartup函数完成对Winsock服务的初始化,使用Socket之前必须调用WSAStartup函数

wVersionRequested:指明程序请求使用的Socket版本。一个WORD(双字节)型数值,其中高位字节指明副版本、低位字节指明主版本

lpWSAData 指向WSADATA数据结构的指针,用来返回请求的Socket的版本信息

例如:

if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) /*MAKEWORD(2,2)表示使用WINSOCK2版本.wsd用来存储系统传回的关于WINSOCK的资料.*/
{
	cout << "WSAStartup Error = " << WSAGetLastError() << "\n";
	return;
}

MAKEWORD(): 创建一个无符号16位整型,通过连接两个给定的无符号参数

WORD MAKEWORD(
BYTE bLow, //指定新变量的低字节序
BYTE bHigh //指定新变量的高字节序;
);

socket

lpWSAData:指向WSADATA数据结构的指针,用来接收Windows Sockets 实现的细节

socket

#include
#include
SOCKET  socket(int af, int type, int protocol);

af :为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。

INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址; AF_INET6 表示 IPv6 地址,如 1110::A0B3:FA21:48AA:1A2B。

type :为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字) 和 SOCK_DGRAM(数据报套接字/无连接的套接字)

protocol :表示传输协议,常用的有 IPPROTO_TCP (TCP 传输协议) 和 IPPTOTO_UDP(UDP 传输协议)。

返回值:SOCKET 类型的句柄

sockaddr

struct sockaddr
{
  unsigned short sa_family; //地址家族 AF
  char sa_data[14];   //14字节协议地址
};

当我们指定sa_family=AF_INET之后,sa_data的形式也就被固定了下来:最前端的2字节用于记录16位的端口,紧接着的4字节用于记录32位的IP地址,最后的8字节清空为零。

sockaddr_in

struct sockaddr_in
{
    unsigned short sin_family; //协议族
    unsigned short sin_port; //存储端口号
    struct in_addr sin_addr;//存储IP地址,使用in_addr这个数据结构
    char sin_zero[8];//空字节
};

sin_zero: 让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节

struct in_addr
{
    unsigned long s_addr;
};

inet_pton

inet_pton是一个IP地址转换函数,可以在将IP地址在 “点分十进制” 和 “二进制整数” 之间转换,而且inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6。

p和n分别代表表达(presentation)和数值(numeric)

#include 
int inet_pton(int af, const char *src, void *dst);点分十进制-----数值格式

af: 是地址簇

src: 是来源地址

dst: 接收转换后的数据。

返回值: 若成功则为1,若输入不是有效的表达式则为0,若出错则为-1

inet_ntop: 数值格式-----点分十进制

const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);     //将数值格式转化为点分十进制的ip地址格式

返回值: 若成功则为指向结构的指针,若出错则为NULL

setsockopt

用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

sockfd:将要被设置套接口的描述字。
level: 选项所在的协议层。支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6
optname: 需要设置的选项名。
optval: 指向存放选项待设置的新值的缓冲区。
optlen: optval缓冲区长度

返回值: 若无错误发生,setsockopt()返回0。

​ 否则的话,返回SOCKET_ERROR错误,应用程序可通过 WSAGetLastError() 获取相应错误代码。

错误代码:

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。

WSAENETDOWN:套接口实现检测到网络子系统失效。

WSAEFAULT:optval不是进程地址空间中的一个有效部分。

WSAEINPROGRESS:一个阻塞的套接口调用正在运行中。

WSAEINVAL:level值非法,或optval中的信息非法。

WSAENETRESET:当SO_KEEPALIVE设置后连接超时。

WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM类型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。

WSAENOTCONN:当设置SO_KEEPALIVE后连接被复位。

WSAENOTSOCK:描述字不是一个套接口。

bind()

将一本地地址与一套接口捆绑。本函数适用于未连接的数据报或流类套接口,在connect()或listen()调用前使用。

当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。

#include 
int PASCAL FAR bind( SOCKET sockaddr, const struct sockaddr FAR* my_addr,int addrlen);

sockaddr: 标识一未捆绑套接口的描述字

sockaddr: 赋予套接口的地址

addrlen: my_addr的长度。

返回值: 如无错误发生,则bind()返回0。否则的话,将返回-1,应用程序可通过WSAGetLastError()获取相应错误代码。

connect()

connect()用于建立与指定socket的连接。

 int connect(SOCKET s, const struct sockaddr * name, int namelen);

返回值: 成功则返回0, 失败返回-1,

recvfrom

从(已连接)套接口上接收数据,并捕获数据发送源的地址。

ssize_t recvfrom (int sockfd,  //已连接套接口的描述字
                  void *buf,  //接收数据缓冲区
                  size_t len,  //缓冲区长度
                  unsigned int flags, //调用操作方式
                  struct sockaddr *from, //指向装有源地址的缓冲区(可选)
                  socket_t *fromlen);  //指向from缓冲区长度值(可选)

ssize_t 相当于 long int

socket_t 相当于int

返回值: 正确接收返回接收到的字节数,失败返回-1.

参数 flags: 以下一个或者多个标志的组合体,可通过“ | ”操作符连在一起

​ MSG_DONTWAIT:操作不会被阻塞。

​ MSG_ERRQUEUE: 指示应该从套接字的错误队列上接收错误值,依据不同的协议,错误值以某种辅佐性消息的方式传递进来,使用者应该提供足够大的缓冲区。导致错误的原封包通过msg_iovec作为一般的数据来传递。导致错误的数据报原目标地址作为msg_name被提供。错误以sock_extended_err结构形态被使用,定义如下

#define SO_EE_ORIGIN_NONE 0

​ #define SO_EE_ORIGIN_LOCAL 1

​ #define SO_EE_ORIGIN_ICMP 2

​ #define SO_EE_ORIGIN_ICMP6 3

​ MSG_PEEK:指示数据接收后,在接收队列中保留原数据,不将其删除,随后的读操作还可以接收相同的数据。

​ MSG_TRUNC:返回封包的实际长度,即使它比所提供的缓冲区更长, 只对packet套接字有效。

sendto()

指向一指定目的地发送数据,sendto()适用于发送未建立连接的UDP数据包 (参数SOCK_DGRAM)。

int sendto(
	int s, //已建好连线的socket,利用UDP协议则不需经过连线操作
	const void * msg, //数据内容
	int len, //msg长度
	unsigned int flags, //一般为0
	const struct sockaddr * to, //sockaddr地址
	int tolen  //sockaddr的结构长度
);

你可能感兴趣的:(C++)