套接口即网络进程的ID;网络通信归根到底即为进程间的通信;套接字中包含了端口号,用来确定进程,一个端口号一次只能分配给一个进程,即端口号与进程是一一对应的;
一、套接字的结构
1、IPv4套接字地址结构
IPv4地址结构命名为sockaddr_in,定义在<netinet/in.h>
头文件中,结构定义如下:
struct sockaddr_in {
sa_family_t sin_family; //IPV4协议为AF_INET,协议族
in_port_t sin_port; //16位端口号,网络字节序列
struct in_addr sin_addr; //32位IP地址
unsigned char sin_zero[8]; //备用域;
};
struct in_addr{
in_addr_t s_addr; //32位IP地址,网络字节序列
} ;
2、通用套接字地址结构
struct sockaddr{
sa_family_t sa_family;
char sa_data[14]
}
通用套接字结构本质上和上面的IPv4套接字是一致的,通用套接字只是在函数调用的过程中用于参数的传递,定义时用sockaddr_in定义,在函数调用时通过类型转换来使用。可以参考sockaddr和sockaddr_in的区别 。套接字结构除了这两种常见的外还有基于IPv6和Unix域的结构sockaddr_in6,sockaddr_un等。
二、相关处理函数
1、字节排序函数
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值
其中,h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换,16bit和32bit分别用于端口号和IP地址。有时可以用任何地址则用INADDR_ANY,INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。
2、字节操作函数
字节操作函数主要是用于操作结构体中的某几个字节,在处理套接字结构中有IP地址等字段,包含0字节却不是C字符串,需要特定的函数来进行处理。
#include <string.h>
void bzero(void *dest,size_t nbytes);
void bcopy(const void *src,void *dest,size_t nbytes);
int bcmp(const void *prt1,const void *ptr2,size_t nbytes); //相等返回0,否则非0
void *memset(void *dest,int c,size_t len);
void *memcpy(void *dest,const void *src,size_t nbytes);
int memcmp(const void *ptr1,const void *ptr2,size_t nbytes); //相等返回0,否则非0
以b打头的函数为支持套接口函数的系统所提供,mem为支持ANSI C库提供的函数;其中,bzero将指定数目的字节设置为0,bcopy将指定数目的字节从源字节串复制到目的字节串。bcmp比较两个字节串,相同返回0。memset将目标中指定数据的字节设置为指定的值(不一定是0),memcpy为复制,memcmp为比较,两者与前面类似。
3、地址转换函数
一般使用ASCII字符串表示IP地址,也就是点分十进制数表示(218.170.19.1),但在套接字中使用32位网络字节序,保存的是二进制值,因此必须进行地址转换。
#include <arpa/inet.h>
in_addr_t inet_addr(const char *straddr); //字符串有效返回网络字节序的IP地址,否则INADDR_NONE
int inet_aton(const char* straddr,struct in_addr *addrp);//字符串有效返回1,否则0
char* inet_ntoa(struct in_addr inaddr); //返回一个字符串指针
int inet_pton(int family, const char* str, void* addr);
//成功返回1,字符串无效返回0,出错返回-1
const char* inet_ntop(int family, const void* addr, char* str, size_t len);
//成功返回结果指针,出错返回NULL
/*说明
*后面两个函数为新函数,支持IPv4和IPv6,family用来指定:AF_INET,AF_INET6
*inet_ntop函数len为目标存储单元大小,str指针就是函数返回值
*/
inet_aton将一个字符串转换为32位网络字节序二进制值,用结构in_addr存储。inet_addr功能相同(废弃,不使用),inet_ntoa进行相反的操作。
4、字节流读取函数
在套接字通信中进行字节读取函数:read(),write()。与I/O中的读取函数略有区别,因为它们输入或输出的字节数比可能比请求的少。
ssize_t write(int fd, const void*buf,size_t nbytes);
ssize_t read(int fd,void *buf,size_t nbyte);