5 Linux网络编程基础API
2015-12-08 21:22
609 查看
[b]5.1 socket地址API[/b]
大端字节序(网络序):高位在低址,低位在高址
小端字节序(主机序):低位在低址,高位在高址
判断,利用联合的特性:
输出4321就是小端,1234就是大端
JAVA虚拟机采用大端
Linux提供4个函数来完成主机字节序和网络字节序之间的转换:
这4个函数,长整型(32bit)函数通常用来转换ip地址,短整型(16bit)函数用来转换端口号,当然不限于此。
通用socket地址
sa_family地址簇类型如下:AF_UNIX,AF_INET, AF_INET6
专用socket地址
实际使用中sockaddr_in需要强制转换sockaddr(sockaddr不够的补0)
ip地址转换函数
inet_addr函数将用点分十进制字符串表示的ipv4地址转化为用网络字节序整数表示的ipv4地址。失败时返回INADDR_NONE。
inet_pton将点分十进制src转化为网络字节序整数标示的ip地址存储与dst指针中 inet_ntop相反
[b]5.2 创建socket [/b]
socket是可读,可写,可控制,可关闭的文件描述符
domain协议族:AF_UNIX,AF_INET, AF_INET6
type:SOCK_STREAM SOCK_DGRAM
protocol:默认0
[b]5.3 命名socket[/b]
将一个socket与socket地址绑定成为给socket命名,服务端通常需要命名socket,因为只有命名后客户端才知道如何连接它。客户端一般采用操作系统自动分配的socket地址
bind成功返回0,失败返回-1并设置errno。其中两中常见的errno是EACCES和EADDRINUSE,含义分别是:
EACCES:被绑定的地址是受保护的地址,仅超级用户能访问。比如普通用户将socket绑定到知名服务端口(端口号为0-1023)。
EADDRINUSE:被绑定的地址正在使用。如将socket绑定到一个处于TIME_WAIT状态的socket地址。
[b]5.4 监听socket [/b]
sockfd是被监听的socket
backlog是处于完全连接的socket的上限 ,通常监听队列中完整连接的上限比backlog值略大(一般为backlog+1)
[b]5.5 接受连接[/b]
sockfd是被监听的socket
addr参数用来获取被接受连接的远端socket地址,长度由addrlen指出
返回一个新连接的socket,该socket唯一标识了被接受的这个连接
[b]5.6 发起连接[/b]
sockfd参数由socket系统调用返回一个socket,一旦连接建立成功sockfd就唯一标识这个连接,客户端通过读写sockfd来与服务器通信
serv_addr是服务器监听socket地址
[b]5.7 关闭连接[/b]
close系统调用并非总是关闭一个连接,而是将fd的引用计数减1.只有当fd的引用计数为0时,才真正关闭连接。多进程程序中,一次fork系统调用默认将使父进程中打开的socket的引用计数加1,因此我们必须在父进程和子进程中都对该socket执行close调用才能将连接关闭。
如果无论如何都要立即终止连接(而不是将socket引用计数减1),可以使用shutdown系统调用(专为网络编程设计的)
howto参数:
SHUT_RD//关闭sockfd上读的这一半。该socket接收缓冲区中的数据都被丢弃
SHUT_WR//关闭sockfd上写的这一半。发送缓冲区中的数据会在真正关闭连接之前全部发送出去,应用程序不可再对该socket文件描述符执行写操作。连接处于半关闭状态。
SHUT_RDWR//同时关闭读写。
由此可见,shutdown能够分别关闭socket上的读或写,或者都关闭。而close在关闭连接时只能将socket上的读和写同时关闭。
[b]5.8 数据读写[/b]
tcp
recv成功时返回实际读取到的数据的长度,它可能小于我们期望的长度len。因此我们可能要多次调用recv,才能读取到完整的数据。recv可能返回0,这意味着通信对方已经关闭连接了。
flags参数:
udp
recvfrome读取sockfd上的数据,buf和len分别制定读缓冲的位置和大小。因为UDP通信没有连接的概念,所以每次读取数据都要获取发送端的地址,即参数src_addr
sendto dest_addr指定接收端的socket地址
这两组函数也可用于面向连接的socket,把最后两个参数设为NULL
通用数据读写函数
[b]5.9 带外标记 [/b]
Linux内核检测到tcp紧急标志时,将通知应用程序有带外数据需要接收。内核通知应用程序带外数据到达的两种常见方式:IO复用产生的异常事件和SIGURG信号。但是,即使应用程序得到了有带外数据需要接收的通知,还需要知道带外数据在数据流中的具体位置,才能准确接收带外数据。
sockatmark判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据。如果是,sockatmark返回1,此时我们就可以利用带MSG_OOB标志的recv调用来接收带外数据。
[b]5.10 地址信息函数 [/b]
获取本地或远端的socket地址存储于address中
[b]5.11 socket选项(重要)[/b]
前者用于读取socket文件描述符,后者用于设置socket文件描述符
sockfd:指定被操作的目标
level:指定要操作哪个协议选项
option_names:指定选项名字
option_value:被操作选项的值
option_len:值的长度
例子:
udp多播:
对服务器而言,有部分socket选项只能在调用listen前针对监听socket设置才有效
[b]5.12 网络信息api [/b]
gethostbyname gethostbyaddr
获取服务信息getservbyname getservbyport
getaddrinfo通过主机名获取ip 通过服务获得端口
getnameinfo函数通过socket地址同时获得以字符串表示的主机名和服务名
大端字节序(网络序):高位在低址,低位在高址
小端字节序(主机序):低位在低址,高位在高址
判断,利用联合的特性:
#include <iostream> using namespace std; int main() { union { int value; char union_bytes[ sizeof(int) ]; } test; test.value = 0x01020304; for(int i = 0;i < 4;i++) cout<<test.union_bytes[i]<<" "; return 0; }
输出4321就是小端,1234就是大端
JAVA虚拟机采用大端
Linux提供4个函数来完成主机字节序和网络字节序之间的转换:
#include <netinet/in.h> unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort);
这4个函数,长整型(32bit)函数通常用来转换ip地址,短整型(16bit)函数用来转换端口号,当然不限于此。
通用socket地址
#include <bits/socket.h> struct sockaddr { sa_family_t sa_family; char sa_data[14]; };
sa_family地址簇类型如下:AF_UNIX,AF_INET, AF_INET6
专用socket地址
#include <sys/un.h> struct sockaddr_in { sa_family_t sin_family; u_int16_t sin_port; struct in_addr sin_addr; }; struct in_addr { u_int32_t s_addr; };
实际使用中sockaddr_in需要强制转换sockaddr(sockaddr不够的补0)
ip地址转换函数
#include <arpa/inet.h> in_addr_t inet_addr(const char* strptr); int inet_aton(const char* cp, struct in_addr* inp); char* inet_ntoa(struct in_addr in);//内部使用静态变量,不可重入
inet_addr函数将用点分十进制字符串表示的ipv4地址转化为用网络字节序整数表示的ipv4地址。失败时返回INADDR_NONE。
#include<arpa/inet.h> int inet_pton(int af, const char* src, void* dst); const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt);
inet_pton将点分十进制src转化为网络字节序整数标示的ip地址存储与dst指针中 inet_ntop相反
[b]5.2 创建socket [/b]
socket是可读,可写,可控制,可关闭的文件描述符
#include<sys/types.h> #include<sys/socket.h> int socket(int domain, int type, int protocol);
domain协议族:AF_UNIX,AF_INET, AF_INET6
type:SOCK_STREAM SOCK_DGRAM
protocol:默认0
[b]5.3 命名socket[/b]
将一个socket与socket地址绑定成为给socket命名,服务端通常需要命名socket,因为只有命名后客户端才知道如何连接它。客户端一般采用操作系统自动分配的socket地址
#include<sys/types.h> #include<sys/socket.h> int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
bind成功返回0,失败返回-1并设置errno。其中两中常见的errno是EACCES和EADDRINUSE,含义分别是:
EACCES:被绑定的地址是受保护的地址,仅超级用户能访问。比如普通用户将socket绑定到知名服务端口(端口号为0-1023)。
EADDRINUSE:被绑定的地址正在使用。如将socket绑定到一个处于TIME_WAIT状态的socket地址。
[b]5.4 监听socket [/b]
#include<sys/types.h> #include<sys/socket.h> int listen(int sockfd, int backlog);
sockfd是被监听的socket
backlog是处于完全连接的socket的上限 ,通常监听队列中完整连接的上限比backlog值略大(一般为backlog+1)
[b]5.5 接受连接[/b]
#include<sys/types.h> #include<sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd是被监听的socket
addr参数用来获取被接受连接的远端socket地址,长度由addrlen指出
返回一个新连接的socket,该socket唯一标识了被接受的这个连接
[b]5.6 发起连接[/b]
#include<sys/types.h> #include<sys/socket.h> int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
sockfd参数由socket系统调用返回一个socket,一旦连接建立成功sockfd就唯一标识这个连接,客户端通过读写sockfd来与服务器通信
serv_addr是服务器监听socket地址
[b]5.7 关闭连接[/b]
#include<unistd.h> int close(fd);
close系统调用并非总是关闭一个连接,而是将fd的引用计数减1.只有当fd的引用计数为0时,才真正关闭连接。多进程程序中,一次fork系统调用默认将使父进程中打开的socket的引用计数加1,因此我们必须在父进程和子进程中都对该socket执行close调用才能将连接关闭。
如果无论如何都要立即终止连接(而不是将socket引用计数减1),可以使用shutdown系统调用(专为网络编程设计的)
#include<sys/socket.h> int shutdonw(int sockfd, int howto);
howto参数:
SHUT_RD//关闭sockfd上读的这一半。该socket接收缓冲区中的数据都被丢弃
SHUT_WR//关闭sockfd上写的这一半。发送缓冲区中的数据会在真正关闭连接之前全部发送出去,应用程序不可再对该socket文件描述符执行写操作。连接处于半关闭状态。
SHUT_RDWR//同时关闭读写。
由此可见,shutdown能够分别关闭socket上的读或写,或者都关闭。而close在关闭连接时只能将socket上的读和写同时关闭。
[b]5.8 数据读写[/b]
tcp
#include<sys/types.h> #include<sys/socket.h> ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t send(int sockfd, const void *buf, size_t len, int flags);
recv成功时返回实际读取到的数据的长度,它可能小于我们期望的长度len。因此我们可能要多次调用recv,才能读取到完整的数据。recv可能返回0,这意味着通信对方已经关闭连接了。
flags参数:
udp
#include<sys/types.h> #include<sys/socket.h> ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen); ssize_t sendto(int sockfd, void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
recvfrome读取sockfd上的数据,buf和len分别制定读缓冲的位置和大小。因为UDP通信没有连接的概念,所以每次读取数据都要获取发送端的地址,即参数src_addr
sendto dest_addr指定接收端的socket地址
这两组函数也可用于面向连接的socket,把最后两个参数设为NULL
通用数据读写函数
#include <sys/socket.h> ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags); ssize_t sendmsg(int sockfd, struct msghdr* msg, int flags); struct msghdr { void* msg_name; //socket地址 socklen_t msg_namelen; struct iovec* msg_iov; int msg_iovlen; void* msg_control; //指向辅助数据的起始位置 socklen_t msg_controllen; int msg_flags; //复制函数中flsgs参数,并在调用过程中更新 }; struct iovec { void* iov_base; //内存起始地址 size_t iov_len; //这块内存的长度 };
[b]5.9 带外标记 [/b]
Linux内核检测到tcp紧急标志时,将通知应用程序有带外数据需要接收。内核通知应用程序带外数据到达的两种常见方式:IO复用产生的异常事件和SIGURG信号。但是,即使应用程序得到了有带外数据需要接收的通知,还需要知道带外数据在数据流中的具体位置,才能准确接收带外数据。
#include <sys/socket.h> int sockatmark(int sockfd);
sockatmark判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据。如果是,sockatmark返回1,此时我们就可以利用带MSG_OOB标志的recv调用来接收带外数据。
[b]5.10 地址信息函数 [/b]
#include <sys/socket.h> int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len); int getpeername(int sockfd, struct sockaddr* address, socklen_t* address_len);
获取本地或远端的socket地址存储于address中
[b]5.11 socket选项(重要)[/b]
#include <sys/socket.h> int getsockopt(int sockfd, int level, int option_name, void* option_value, socklen_t* restrict option_len); int setsockopt(int sockfd, int level, int option_name, const void* option_value, socklen_t option_len);
前者用于读取socket文件描述符,后者用于设置socket文件描述符
sockfd:指定被操作的目标
level:指定要操作哪个协议选项
option_names:指定选项名字
option_value:被操作选项的值
option_len:值的长度
例子:
udp多播:
setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop)); //加入多播组 setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)); //退出多播组 setsockopt(sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));
对服务器而言,有部分socket选项只能在调用listen前针对监听socket设置才有效
[b]5.12 网络信息api [/b]
gethostbyname gethostbyaddr
#include<netdb.h> struct hostent* gethostbyname(const char* name); struct hostent* gethostbyaddr(const void* addr, size_t len, int type); struct hostent { char* h_name; char** h_aliases; int h_addrtype; int h_length; char** h_addr_list; };
获取服务信息getservbyname getservbyport
#include<netdb.h> struct servent* getservbyname(const char* name, const char* proto); struct servent* getservbyport(int port, const char* proto); struct servent { char* s_name; char** s_aliases; int s_port; char* s_proto; };
getaddrinfo通过主机名获取ip 通过服务获得端口
#include<netdb.h> int getaddrinfo(const char* hostname, const char* service, const struct addrinfo* hints, struct addrinfo** result); struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; char* ai_canonname; struct sockaddr* ai_addr; struct addrinfo* ai_next; };
getnameinfo函数通过socket地址同时获得以字符串表示的主机名和服务名
#include<netdb.h> int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, int flags);
相关文章推荐
- kernel: TCP: time wait bucket table overflow错误的解决办法
- 【解析HTML】HTML解析,网络爬虫
- 猫哥网络编程系列:详解 BAT 面试题
- 关于XMLHttpRequest.open()设置提交方式 (POST,GET)
- iOS 9 请求网络数据出现:App Transport Security has blocked a cleartext HTTP (http://) resource load since it
- hdu 3572 Task Schedule 网络流
- POJ_P1273 Drainage Ditches(模板题+网络流)
- http_cracker.sh
- AFNetworking+Nginx+HTTPS服务器通信
- HttpHelper
- Triangle Count算法
- Android实时监听网络状态
- 关于socket tcp/ip的理解
- 百度地图自定义图层----BMapTileCutterJava切图工具网络版
- RBM(受限波尔兹曼机)和 DBN(深信度神经网络)
- TCP三次握手
- java 发送http请求
- 网络程序开发实验报告
- Linux基础网络设置
- 调用 WebService 请求因 HTTP 状态 407 失败