SOCKET地址API

主机字节序和网络字节序:

       大端字节序是一个数的高位字节存储在内存的低地址位;小端字节序是一个数的高位字节序在内存的高位地址位;主机字节序是小端字节序;网络字节序是大端字节序;JAVA虚拟机是大端字节序。

       Linux下提供了4个函数完成大小端的转换,即为:
#include <netinet/in.h>

unsigned long int htonl(unsigned long int hostlong);

unsigned short htons(unsigned short hostshort);

unsigned long int ntohl(unsigned long int netlong);

unsigned short int ntohs(unsigned short int netshort);

通用SOCKET地址:

#include <bits/socket.h>

struct sockaddr

{

sa_family_t sa_family;//AF_UNIX AF_INET AF_INET6

char sa_data[14];      //socket地址值,由于各个协议族长度不一,有如下的结构体
}

struct socketaddr_storage

{

sa_family_t sa_family;

unsigned long int __ss_allgn;

char __ss_pading[128 -sizeof(__ss_align)];

}

专用socket地址:

#include <sys/un,h>

struct sockaddr_un

{

sa_family_t sin_family;

char sun_path[108];

}

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;

};

struct sockaddr_in6

{
sa_family_t  sin6_family

u_int16_t sin6_port;

u_int32_t sin6_flowinfo;

struct in6_addr sin6_addr;

u_int32_t sin6_scope_id;

};

struct in6_addr

{

unsigned char sa_addr[16];

};

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

 

int inet_pton(int af ,char*src,void* dst);

const char* inet_ntop(int af , const char *src ,char *dst  ,socklen_t cnt);

其中cnt参数为下列两个参数

#include <netinet/in.h>

#define INET_ADDRSTRLEN 16

#define INET6_ADDRSTRLEN 46

创建socket

#include <sys/types.h>

#include <sys/socket.h>

int socket(int domain ,int type ,int protocol);

domain:PE_INET / PE_INET6 / PE_UNIX

type:SOCK_STREAM / SOCK_UGRAM / SOCK_DGRAM

protocol:0

失败返回-1

命名socket

#include <sys/types.h>

#include <sys/socket.h>

int bind(int socketfd,const struct sokaddr* my_addr ,socklen_t addlen);

成功返回0,失败为-1,errno是EACCES和EADDRINUSE

监听socket

#include <sys/socket.h>

int listen(int sockfd,int backlog);

backlog指的是监听队列的最大值,经典值为5,监听个数个backlog+1

接受连接

#include <sys/types.h>

#include <sys/socket.h>

int accept(int sockfd , struct sockaddr * addr ,socklen_t addrlen);

accept不关心socket的状态,即使断网了他也可以返回成功

发起连接

#include <sys/types.h>

#include <sys/socket.h>

int connect(int sockfd,const sockaddr *serv_addr , socklen_t addrlen);

关闭连接

#include <sys/socket.h>

int close(int fd);并不是立即关闭,而是将socket的fd的引用计数减1,必须父子进程都关闭才生效,如果要关闭,那么用

int shutdown(int sockfd ,int howto);

其中howto的值可以设置为SHUT_RD (关闭读,可以写)/ SHUT_WR(关闭写,可以读) / SHUT_RDWR(读写都关闭)

成功返回0,失败返回-1,并设置errno的值;

数据读写

tcp数据读写

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recv(int sockfd , void * buf ,size_t len ,int flags);

flags通常设置为0,返回值>0,返回值=0表示对方关闭连接了,返回值=-1代表出错了;

ssize_t send(int sockfd ,const void*buf , size_t len, int flags);

flags通常设置为0,返回值大于0代表写入成功,失败返回-1

flags的值可以是:

MSG_CONFIRM 数据链路层监听对方回应,直到有回复。仅仅用于SOCK_DGRAM和SOCK_RAW

MSG_DONTROUTE直接发送到本机,不经过路由,明确直到数据是发往本机的

MSG_MORE 告诉内核应用程序还有更多的数据要发送,内核超时等待写入TCP缓冲区一并发送,解决发过多的小报文的问题

MSG_WAITALL 读操作读到指定的字节才返回

MSG_PEEK 窥探缓存中的数据,此次读操作不会导致数据被清除

MSG_OOB 发送或接受紧急数据

NSG_NOSUGNAL 往读端关闭管道,或者socket连接中写数据不引发SIGPIPE信号

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 , const void *buf ,size_t len , int flags,cosnt struct sockaddr* dst_addr .socklen_t* addrlen);

值得一提的是这两个函数也可设置为stream之间的读写,只需要把最后的指针设置为NULL

外带数据

可以用 int sockatmark(int sockfd);判断下一个读到的数据是否是外带数据,如果是返回1 ,否则返回0;

地址信息函数

int getsockname(int sockfd , sockaddr* address ,socklen_t address_len); //获取本端的socket地址

int getpeername(int sockfd .sockaddr* address , socklen_t address_len); //获取对段的socket地址

socket选项

SO_DEBUG

SO_REUSEADDR

SO_TYPE

SO_ERROR

SO_DONTROUTE

SO_RECVBUF

SO_SNDBUF

SO_KEEPLIVE

SO_OBBINLINE

SO_LINGER

SO_RCVLOWAT

SO_SNDLOWAT

SO_RCVTIMEO

SO_SNDTIMEO

IP_TOS

IP_TTL

IPV6_NEXTHOP

IPV6_RECVPKTINFO

IPV6_DONTFRAG

IPV6_RECVCLASS

TCP_MAXSEG

TCP_NODELAY

重要的socket选项:
0)SO_REUSEADDR

解决TIME_WAIT

int sock = socket(PF_INET , SOCK_STREAM , 0);

assert(sock >= 0);

int reuse = 1;

setsockopt(sock , SO_SOCKET , SO_REUESEADDR , &reuse , sizeof(reuse));

socketaddr_in address;

bzero(&address , sizeof(address));

address,sin_family = AF_INET;

                 ....

也可以在 /proc/sys/net/ipv4/tcp_wt_recycle中设置;

1)SO_RCVBUF 和SO_SNDBUF

setsockopt(sockfd , SO_SOCKET , SO_RCVBUF , &buf ,sizeof(buf));

getsockopt(sockfd , SO_SOCKET ,SO_RCVBUF , &buf,sizeof(buf));

2)SO_RCVLOWAT和SO_SNDLOWAT

这两个选项的作用是,一般在IO复用时候使用,当超过低水位时,就通知可读和可写事件

3)SO_LINGER

strucr linger

{

int l_offset;//开启(非0)关闭(0)

int l_linger; //滞留时间

}

l_offset = 0 ,按默认的来

l_osset >0 ,l_linger =0;立即关闭close,丢弃数据,并向对端发送复位

l_offset>0,l_linger >0;若是阻塞的,等待l_linger时间,close返回-1

                                   若是非堵塞的,close立即返回,通过返回值和errno判断数据是否发送完毕

网络信息API

#include <sockdb.h>

hostent* gethostbyname(const char * name);

hostent* gethostbyaddr(const void * addr ,size_t len ,int type);

其中

struct hostent{

char* h_name; //主机名字

char**h_aliases;//主机别名,可有多个

int h_adrtype; //地址类型

int h_length; //地址长度

char** h_addr_list;//按网络字节序列出的IP地址

};

servent* getservbyname(const char* name ,const char * proto);

servent* getservbyport(int port ,const char* proto);

struct servent

{

char* s_name; //服务名字

char** s_aliases;//服务别名列表

int s_port;//端口号

char* s_proto;//服务类型,tcp/udp

}

getaddrinfo

int getaddrinfo(const char* hostname , const char * service ,const struct addrinfo* hints , addrinfo ** result);

struct addrinfo{

int ai_flags;

int ai_family;

int ai_socktype;//SOCK_STREAM SOCK_DGRAM

int ai_protocol; // 0 nomal

socklen_t ai_addelen;

char* al_canonname;

struct so

ckaddr* ai_addr;

struct sockinfo *ai_nest;

}

flag选项:

AI_PASSIVE

AI_CANONNAME

AI_NUMERICSERV

AI_V4MAPPED

AI_ALL

AO_ADDRCONFIG

getnameinfo

int getnameinfo(const sockaddr* sockaddr , socklen_t addrlen , char* host ,socklen_t hostlen ,char serv, socklen_t serlen ,int flags);

NI_NAMEREQD

NI_DGRAM

NI_NUMERICHOST

NI_NUMEROCSERV

NI_NOFQDN

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐