int bind(int sock, struct sockaddr *addr, socklen_t addrlen); //Linux int bind(SOCKET sock, const struct sockaddr *addr, int addrlen); //Windowssock 为 socket 文件描述符,addr 为 sockaddr 结构体变量的指针,addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。
//创建套接字 int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建sockaddr_in结构体变量 struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充 serv_addr.sin_family = AF_INET; //使用IPv4地址 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址 serv_addr.sin_port = htons(1234); //端口 //将套接字和IP、端口绑定 bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));这里我们使用 sockaddr_in 结构体,然后再强制转换为 sockaddr 类型,后边会讲解为什么这样做。
struct sockaddr_in{ sa_family_t sin_family; //地址族(Address Family),也就是地址类型 uint16_t sin_port; //16位的端口号 struct in_addr sin_addr; //32位IP地址 char sin_zero[8]; //不使用,一般用0填充 };1) sin_family 和 socket() 的第一个参数的含义相同,取值也要保持一致。
struct in_addr{ in_addr_t s_addr; //32位的IP地址 };in_addr_t 在头文件 <netinet/in.h> 中定义,等价于 unsigned long,长度为4个字节。也就是说,s_addr 是一个整数,而IP地址是一个字符串,所以需要 inet_addr() 函数进行转换,例如:
unsigned long ip = inet_addr("127.0.0.1"); printf("%ld\n", ip);运行结果:
图解 sockaddr_in 结构体
struct sockaddr{ sa_family_t sin_family; //地址族(Address Family),也就是地址类型 char sa_data[14]; //IP地址和端口号 };下图是 sockaddr 与 sockaddr_in 的对比(括号中的数字表示所占用的字节数):
struct sockaddr_in6 { sa_family_t sin6_family; //(2)地址类型,取值为AF_INET6 in_port_t sin6_port; //(2)16位端口号 uint32_t sin6_flowinfo; //(4)IPv6流信息 struct in6_addr sin6_addr; //(4)具体的IPv6地址 uint32_t sin6_scope_id; //(4)接口范围ID };正是由于通用结构体 sockaddr 使用不便,才针对不同的地址类型定义了不同的结构体。
int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen); //Linux int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen); //Windows各个参数的说明和 bind() 相同,不再赘述。
本文链接:http://task.lmcjl.com/news/16300.html