WindowsSocket编程(tcp篇)
一、头文件和库
1、导入头文件winsock2.h
2、链接ws2_32.lib
库
链接库步骤:快捷键Alt + F7 --> 配置属性 --> 输入 --> 附加依赖项
或快捷键Alt + F7 --> 配置属性 --> 输入 --> 附加依赖项
二、Winsock初始化
#include <winsock2.h>
/*进行Winsock编程时,必须首先调用WSAStartup函数,设置程序中用到的Winsock版本,并初始化相应版本的库*/
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSADATA);
参数1:Winsock版本:可使用宏MAKEWORD(1,2);
该宏返回字节类型数据0x0201;
参数2:WSADATA
结构体的指针类型。
返回值:成功时返回0,失败时返回非0的错误代码。
#include <winsock2.h>
/*程序结束之前调用此函数*/
int WSACleanup(void); //成功时返回0,失败时返回SOCKET_ERROR
例子
WSADATA wsaData;
int WSAStartup( MAKEWORD(1,2), &wsaData );
WSACleanup();
三、Windows套接字相关函数
SOCEKT socket( int af, int type, int protocol );
参数1:协议族。可选参数为(PF_INET, PF_INET6, PF_LOCAL, PF_PACKET, PF_IPX);有些地方也将PF写作AF,两者是相同的。
参数2:套接字类型。可选参数(SOCK_STREAM, SOCK_DGRAM);
参数3:协议的最终选择。大部分情况可以直接传递参数0,可选参数(IPPROTO_TCP, IPPROTO_UDP);
返回值:成功时返回套接字句柄,失败时返回INVALID_SOCKET;
int bind( SOCKET s, const struct sockadd * name, int namelen );
参数1:要分配地址信息(IP地址和端口号)的SOCKET句柄
参数2:存有地址信息的结构体变量
参数3:第二个结构体变量的长度
返回值:成功时返回0,失败时返回SOCKET_ERROR;
int listen( SOCKET s, int backlog );
参数1:希望进入连接等待的套接字句柄,传递的套接字句柄成为服务器端套接字(监听套接字)
参数2:连接请求队列的长度,若为5,则最多使5个连接请求进入队列
返回值:成功时返回0,失败时返回SOCKET_ERROR;
int accpt( SOCKET s, const struct sockadd * addr, int * addrlen );
参数1:服务器端套接字句柄
参数2:保存发起请求的客户端地址信息,传入参数为sockaddr_in结构体,需使用(sockaddr*)强转
参数3:第二个参数sockadd结构体的长度
返回值:成功时返回0,失败时返回SOCKET_ERROR;
int connect( SOCKET s, const struct sockadd * name, int namelen );
参数1:客户端套接字句柄
参数2:保存目标服务器的信息,传入参数为sockaddr_in结构体,需使用(sockaddr*)强转
参数3:第二个参数值的长度
返回值:成功时返回0,失败时返回SOCKET_ERROR;
int closesocket( SOCKET s );
参数1:要关闭的套接字句柄
返回值:成功时返回0,失败时返回SOCKET_ERROR;
四、Windows的I/O函数
int send( SOCKET s, const char * buf, int len, int flags );
参数1:表示数据传输对象连接的套接字句柄值
参数2:保存待传输数据的缓冲地址值
参数3:要传输的字节数
参数4:要传输信息时用到的多种选项信息
返回值:成功时返回传输字节数,失败时返回SOCKET_ERROR;
int recv( SOCKET s, const char * buf, int len, int flags );
参数1:表示数据接收对象连接的套接字句柄值
参数2:保存接收数据的缓冲地址值
参数3:能够接收的最大字节数
参数4:接收数据时用到的多种选项信息
返回值:成功时返回接收的字节数(收到EOF时为0),失败时返回SOCKET_ERROR;
五、结构体
struct sockaddr_in{
sa_family_t sin_family; //地址族。可选参数为(AF_INET, AF_INET6, AF_LOCAL);
uint16_t sin_port; //16位端口号,以网络字节序保存
struct in_arrd sin_addr; //32位的IP地址信息,以网络字节序保存。使用inet_addr(INADDR_ANY)可直接获取本机IP
char sin_zero[8]; //无特殊含义,必须填充位0
}
struct in_addr{
Inaddr_t s_addr;
}
六、字节序
大端序(网络字节序):高字节存放在低位地址
小端序:高字节存放在高位地址
字节序转换:
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
htons中的h代表主机(host)字节序;
htons中的n代表主机(network)字节序。
另外,以s作为后缀的函数中,s表示两个字节的short,用于端口号转换。以l作为后缀的函数中,l表示4个字节的long,用于IP地址转换。
七、网络地址的初始化与分配
1、将字符串信息转化为网络字节序
in_addr_t inet_addr(const char* string); //参数为ip地址。成功时返回32位大端序整数值,失败时返回INADDR_NONE
2、将网络字节序整型转化为字符串ip地址
char* inet_ntoa(struct in_addr addr); //成功时返回字符串ip值,失败返回-1
八、域名及IP的转换
1、通过域名获得IP
/* 传入字符串域名,返回IP地址。成功时返回struct地址,失败时返回NULL */
#include <winsock2.h>
struct hostent * gethostbyname(const char * name);
2、通过IP获得域名
/* 传入IP,获得对应的域名信息。成功时返回struct地址,失败时返回NULL */
#include <winsock2.h>
struct hostent * gethostbyaddr(const char * addr, int len, int type);
参数1:含有IP地址信息的in_addr结构体指针,为了同时传递IPv4地址之外的其他信息,该变量声明为char指针
参数2:向第一个参数传递地址的字节数,IPv4时为4,IPv6时为16
参数3:传递地址族信息,IPv4时为AF_INET,IPv6时为AF_INET6
下一篇: UDP协议编程