luoxn28 / ThinkInTechnology

think in technology
Apache License 2.0
15 stars 6 forks source link

深入理解Linux基本套接字编程 #1

Open luoxn28 opened 7 years ago

luoxn28 commented 7 years ago

Linux网络编程中,套接字编程是重要的知识,因为操作系统就是通过提供套接字来为进程提供网络通信能力的。在使用C/C++开源网络库(比如libevent/nginx/muduo)的同时,如果不去了解套接字编程,往往对这些框架或者组件没有原理上的认识。学习套接字编程,需要知道常用的套接字函数有哪些,了解这些函数在使用中的注意事项。

套接字地址结构

struct in_addr {
    in_addr_t  s_addr;  // 32-bit IPv4 address
                        //network byte ordered
}
struct sockaddr_in {
    sa_family_t  sin_family;     //AF_INET
    in_port_t    sin_port;       //16-bit TCP or UDP port nummber, network byte ordered
    struct in_addr    sin_addr;  //32-bit IPv4 address, network byte ordered
    char     sin_zero[8];        //unused
}

sockaddr_in是网络套接字地址结构,大小为16字节,定义在<netinet/in>头文件中,一般我们在程序中是使用该结构体,但是作为参数传递给套接字函数时需要强转为sockaddr类型,注意该结构体中port和addr成员是网络序的(大端结构)。

struct sockaddr {
    sa_family_t  sa_family;     //address family: AF_XXX value
    char        sa_data[14];    //protocol-specific address
}

sockaddr是通过套接字地址结构,当作为参数传递给套接字函数时,套接字地址结构总是以指针方式来使用,比如bind/accept/connect函数等。

htons、ntohs、htonl和ntohl函数

#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);

Linux提供了4个函数来完成主机字节序和网络字节序之间的转换。这些函数名字中,h表示host,n表示net,s表示short,l表示long。使用这些函数时,我们并不关心主机字节序和网络字节序的真实值,也就是为大端还是小端,要做的只是调用适当的函数在主机和网络字节序之间转换为某个特定值。

ient_aton、inet_addr和inet_ntoa函数

#include <arpa/inet.h>
int inet_aton(const char *strptr, struct in_addr *addrptr); // 返回:若字符有效则为1,否则为0
in_addr_t inet_addr(const char *strptr); // 返回:若字符串有效则为32位二进制网络字节序地址,否则为INADDR_NONE
char *inet_ntoa(struct in_addr inaddr);  // 返回:指向一个点分十进制数串的地址

inet_aton、inet_addr和inet_ntoa在点分十进制数串(比如"192.168.1.1")与它长度为32位的网络字节序二进制值间转换IPv4地址。在调用inet_addr时需特别注意,inet_ntoa函数的输入参数是unsigned int型的ip地址,返回的却是指向ip字符串的指针,很明显,ip字符串所占的内存是在函数内部分配的,而我们并不需要释放该内存,所以,它分配的内存是静态的,内部使用static变量存储IP点分十进制数串,也就是说第二次调用该函数时会覆盖第一次调用该函数时的内存。

inet_pton和inet_ntop函数

#include <arpa/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr); // 返回:成功为1,输入不是有效表达式返回0,出错为-1
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len); // 返回:成功为指向结果的指针,出错为NULL

这两个函数对于IPv4和IPv6都适用,p代表表达式(presentation)、n表示数值(numeric)。第一个函数尝试转化由strptr指针所指的字符串,通过addptr指针存放二进制结果,成功返回1,如果对指定的family而言输入的不是有效的表达格式,那么返回0 inet_ntop进行相反的操作,如果len的值太小,不足以存放表达式结果,则返回一个空指针,并置error为ENOSPC。inet_ntop函数的strptr参数不可以是一个空指针,调用者必须为目标存储单元分配内存并制定其大小,调用成功时,这个指针就是该函数返回值。

socket函数

为了执行网络IO,一个进程必须做的第一件事就是调用socket函数,指定期望的通信协议类型(比如使用IPv4的TCP、使用IPv6的UDP、Unix域字节流协议)和套接字类型(字节流、数据报或原始套接字)。

#include <sys/socket.h>
int socket(int family, int type, int protocol); // 成功返回非负描述符,出错-1

family指定协议族,type指定套接字类型,protocol指定某个协议类型常值,或者设为0。 family的值有:

felixzhooou commented 7 years ago

文中的截图来自哪本书啊?

luoxn28 commented 7 years ago

UNIX网络编程卷1:套接字联网API(第3版)

felixzhooou commented 7 years ago

Thank you for replyling 2017年6月2日星期五,骆向南 notifications@github.com 写道:

UNIX网络编程卷1:套接字联网API(第3版)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/luoxn28/ThinkInTechnology/issues/1#issuecomment-305787239, or mute the thread https://github.com/notifications/unsubscribe-auth/AYyucCoNqDMyCjYXkJYiL3G7QqM5yLt4ks5sAA5cgaJpZM4KrXEt .