编程语言
1000
在Window中也提供了套接字通信的API,这些API函数与Linux平台的API函数几乎相同,以至于很多人认为套接字通信的API函数库只有一套,看一下这些Windows平台的套接字函数:
1. 初始化套接字环境
使用Windows中的套接字函数需要额外包含对应的头文件以及加载响应的动态库:
// 使用包含的头文件 include <winsock2.h> // 使用的套接字库 ws2_32.dll
在Windows中使用套接字需要先加载套接字库(套接字环境),最后需要释放套接字资源。
// 初始化Winsock库 // 返回值: 成功返回0,失败返回SOCKET_ERROR。 WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
- 参数:
- wVersionRequested: 使用的Windows Socket的版本, 一般使用的版本是 2.2
- 初始化这个 MAKEWORD(2, 2);参数
- lpWSAData:一个WSADATA结构指针, 这是一个传入参数
- 创建一个 WSADATA 类型的变量, 将地址传递给该函数的第二个参数
- wVersionRequested: 使用的Windows Socket的版本, 一般使用的版本是 2.2
注销Winsock相关库,函数调用成功返回0,失败返回 SOCKET_ERROR。
int WSACleanup (void);
使用举例:
WSAData wsa; // 初始化套接字库 WSAStartup(MAKEWORD(2, 2), &wsa); // ....... // 注销Winsock相关库 WSACleanup();
2. 套接字通信函数
基于Linux的套接字通信流程是最全面的一套通信流程,如果是在某个框架中进行套接字通信,通信流程只会更简单,直接使用window的套接字api进行套接字通信,和Linux平台上的通信流程完全相同。
2.1 结构体
/////////////////////////////////////////////////////////////////////// /////////////////////////////// Windows /////////////////////////////// /////////////////////////////////////////////////////////////////////// typedef struct in_addr { union { struct{ unsigned char s_b1,s_b2, s_b3,s_b4;} S_un_b; struct{ unsigned short s_w1, s_w2;} S_un_w; unsigned long S_addr; // 存储IP地址 } S_un; }IN_ADDR; struct sockaddr_in { short int sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ unsigned char sin_zero[8]; /* Same size as struct sockaddr */ }; /////////////////////////////////////////////////////////////////////// //////////////////////////////// Linux //////////////////////////////// /////////////////////////////////////////////////////////////////////// typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef uint16_t in_port_t; typedef uint32_t in_addr_t; typedef unsigned short int sa_family_t; struct in_addr { in_addr_t s_addr; }; // sizeof(struct sockaddr) == sizeof(struct sockaddr_in) struct sockaddr_in { sa_family_t sin_family; /* 地址族协议: AF_INET */ in_port_t sin_port; /* 端口, 2字节-> 大端 */ struct in_addr sin_addr; /* IP地址, 4字节 -> 大端 */ /* 填充 8字节 */ unsigned char sin_zero[sizeof (struct sockaddr) - sizeof(sin_family) - sizeof (in_port_t) - sizeof (struct in_addr)]; };
2.2 大小端转换函数
// 主机字节序 -> 网络字节序 u_short htons (u_short hostshort ); u_long htonl ( u_long hostlong); // 网络字节序 -> 主机字节序 u_short ntohs (u_short netshort ); u_long ntohl ( u_long netlong); // linux函数, window上没有这两个函数 inet_ntop(); inet_pton(); // windows 和 linux 都使用, 只能处理ipv4的ip地址 // 点分十进制IP -> 大端整形 unsigned long inet_addr (const char FAR * cp); // windows in_addr_t inet_addr (const char *cp); // linux // 大端整形 -> 点分十进制IP // window, linux相同 char* inet_ntoa(struct in_addr in);
2.3 套接字函数
window的api中套接字对应的类型是 SOCKET 类型, linux中是 int 类型, 本质是一样的
// 创建一个套接字 // 返回值: 成功返回套接字, 失败返回INVALID_SOCKET SOCKET socket(int af,int type,int protocal); 参数: - af: 地址族协议 - ipv4: AF_INET (windows/linux) - PF_INET (windows) - AF_INET == PF_INET - type: 和linux一样 - SOCK_STREAM - SOCK_DGRAM - protocal: 一般写0 即可 - 在windows上的另一种写法 - IPPROTO_TCP, 使用指定的流式协议中的tcp协议 - IPPROTO_UDP, 使用指定的报式协议中的udp协议 // 关键字: FAR NEAR, 这两个关键字在32/64位机上是没有意义的, 指定的内存的寻址方式 // 套接字绑定本地IP和端口 // 返回值: 成功返回0,失败返回SOCKET_ERROR int bind(SOCKET s,const struct sockaddr FAR* name, int namelen); // 设置监听 // 返回值: 成功返回0,失败返回SOCKET_ERROR int listen(SOCKET s,int backlog); // 等待并接受客户端连接 // 返回值: 成功返回用于的套接字,失败返回INVALID_SOCKET。 SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen ); // 连接服务器 // 返回值: 成功返回0,失败返回SOCKET_ERROR int connect (SOCKET s,const struct sockaddr FAR* name,int namelen ); // 在Qt中connect用户信号槽的连接, 如果要使用windows api 中的 connect 需要在函数名前加:: ::connect(sock, (struct sockaddr*)&addr, sizeof(addr)); // 接收数据 // 返回值: 成功时返回接收的字节数,收到EOF时为0,失败时返回SOCKET_ERROR。 // ==0 代表对方已经断开了连接 int recv (SOCKET s,char FAR* buf,int len,int flags); // 发送数据 // 返回值: 成功返回传输字节数,失败返回SOCKET_ERROR。 int send (SOCKET s,const char FAR * buf, int len,int flags); // 关闭套接字 // 返回值: 成功返回0,失败返回SOCKET_ERROR int closesocket (SOCKET s); // 在linux中使用的函数是: int close(int fd); //----------------------- udp 通信函数 ------------------------- // 接收数据 int recvfrom(SOCKET s,char FAR *buf,int len,int flags, struct sockaddr FAR *from,int FAR *fromlen); // 发送数据 int sendto(SOCKET s,const char FAR *buf,int len,int flags, const struct sockaddr FAR *to,int tolen);