套接字编程基础

       网络编程,从某种程度上说就是进程间通信,套接口类似于进程的ID,通过IP地址指定通信的主机,通过端口号指定和主机上的那个进程通信,也就是通过IP+端口号唯一确定了通信的进程。

通用套接口结构

结构:

struct sockaddr{

       uint8_t sa_len;//数据长度

       sa_family sa_family;//协议名

       char sa_data[14];//14位的协议地址

}

头文件:sys/socket.h

说明:通用套接字接口结构

 

Posix.lg中数据类型

数据类型

说明

头文件

int8_t

带符号的8位整数

sys/types.h

uint8_t

无符号的8位整数

sys/types.h

int16_t

带符号的16位整数

sys/types.h

uint16_t

无符号的16位整数

sys/types.h

int32_t

带符号的32位整数

sys/types.h

uint32_t

无符号的32位整数

sys/types.h

sa_family_t

套接口地址结构的地址簇

sys/socket.h

socklen_t

套接口地址的长度,一般为uint32_t

sys/socket.h

in_port_t

TCP或UDP端口,一般为uint16_t

netinet/in.h

in_addr_t

Ipv4地址,一般为uint32_t

netinet/in.h

 

IPv4套接口地址数据结构

结构:

    struct sockaddr_in {

     short int sin_family; //IPV4协议为AF_INET

     unsigned short int sin_port;//16位端口号,网络字节序列

     struct in_addr sin_addr; //

unsigned char sin_zero[8]; //备用域,为了和struct sockaddr字

//节数保持相同;

  };

    struct in_addr{

       in_addr_t s_addr;//32位IP地址,网络字节序列

} ;

头文件:neitnet/in.h

说明:

常用函数

字节排序函数

计算机内存中有两种数据存储方式,一种为小端字节序,也就是低地址存储数据低字节,高地址存储数据高字节;一种为大端字节序,也就是低地址存储高字节,高地址存储低字节。网络字节序采用大端字节序,而主机字节序有可能为小端字节序,因此,存在着字节序的转换问题。

函数:

uint16_t htons(uint16_t hostvalue);

uint32_t htonl(uint32_t hostvalue);

uint16_t ntohs(uint16_t netvalue);

uint32_t ntohl(uint32_t netvalue);

头文件:netinet/in.h

说明:函数中h表示host,n表示network,s表示short,l表示long,一般而言,使用htonshentohs转换端口号,htonl和ntohl转换IP地址。

字节操作函数

字节操作函数主要是用于读取结构体中的某几个字节。

函数:

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

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

头文件:string.h

说明:以b打头的函数为支持套接口函数的系统所提供,mem为支持ANSI C库提供的函数;其中,bzero将制定的起始地址设置为0(nbytes表示字长),bcopy和memcpy为复制,bcmp和memcmp为比较,memset将目标中指定数据的字节设置为指定的值。

地址转换函数

在TCP/IP的网络上,使用ASCII地址,也就是使用“.”隔开的4个十进制数表示,但在套接字中使用32位网络字节序,因此必须进行地址转换。

函数: in_addr_t inet_addr(const char *straddr);

       int inet_aton(const char* straddr,struct in_addr *addrp);

       char* inet_ntoa(struct in_addr inaddr);

头文件:sys/socket.h netinet/in.h arpa/inet.h

说明:

inet_addr成功返回32位网络字节序地址,出错返回INADDR_NONE。INADDR_NONE为linux定义的一个常数,是一个不存在的ip地址;

inet_aton将ASCII转换成网络字节序的32位二进制值,输入的ASCII放在straddr中,转换后放在addrp中,成功返回1,失败返回0;

   inet_ntoa将32位二进制地址转换成ASCII地址,成功返回ASCII值,失败返回NULL。

字节流读取函数

         仍然为read和write函数,和文件I/O不同在于其读取的字节数可能比要求的少,但不是读取错误。

创建套接口函数

函数:int socket(int family,int type,int protocol);

头文件:sys/socket.h

说明:创建一个套接口描述字,也就是套接字,返回值大于等于0,表示成功,否则表示失败,protocol一般为0,其中family的取值如下:

AF_LOCAL  UNIX协议簇       AF_ROUTE  路由套接口

AF_INET   IPv4协议         AF_INET6  IPv6协议

AF_KEY    密钥套接口

type的取值如下:

    SOCK_STREAM  TCP套接口            SOCK_DGRAM      UDP套接口

    SOCK_PACKET  支持数据链路访问     SOCK_RAW     原始套接口

套接口绑定函数

函数:int bind(int sockd,const struct sockaddr *myaddr,socklen_t addrlen)

头文件:sys/socket.h

说明:成功返回值为0,失败返回-1,并设置errno值。该函数的调用不是必须的,只有需要和固定的某个特定网络地址和端口通信时才会使用到,一般而言调用connect和listen函数时,linux内核会自动分配一个地址和端口号。该函数的调用,对于服务器端而言,myaddr必须为从该地址接受客户信息的地址,对于客户端而言,myaddr指定了套接口的源地址。对于端口号,可以任意指定,但是不能为系统保留端口。此外,bind允许内核指定地址,当套接口设定port为0时,表示有内核指定端口号,设置sin_addr为INADDR_ANY时,有内核指定IP地址,

套接口链接函数(客户端使用)

函数:int connect(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen)

头文件:sys/socket.h    sys/types.h

说明:链接成功返回0,失败返回-1,并设置errno的值

套接口监听函数(服务器端使用)

函数:(1)int listen(int sockfd,int backlog);

      (2)int accept(int sockfd,const struct sockaddr *myaddr,socklen_t *addrlen)

头文件:sys/socket.h

说明:

listen用来监听,其中backlog表示内核为此套接口设定的接受客户端请求的最大连接数。成功返回0,失败返回-1,并设置errno的值。

accept主要用来处理各个连接,其功能为从已经完成的来你接队列的队头返回下一个已完成连接,如果已完成连接队列为空,则进程休眠。返回非负描述字表示成功,出错返回-1。成功时,返回值用来标识新建立的链接。其与参数sockfd的区别在于,监听套接口描述字只有一个,而且一直存在,而函数返回值表示已连接的套接口描述字,当连接断开时就关闭该描述字,如果不需要客户端的地址和端口信息,可以将第二个和第三个参数设置为空指针。

获取本地或远程协议地址

函数:

(1) getsockname(int sockfd,struct sockaddr *localaddr,socklen_t *addrlen);

(2) getpeername(int sockfd,struct sockaddr *peeraddr,socklen_t *addrlen);

头文件:sys/socket.h

说明:(1)返回本地协议地址,(2)返回远程协议地址

当不调用bind或调用bind没有指定本地IP地址和端口时,可以调用函数getsockname来返回内核分配的本地IP地址和端口号,还可以获取到套接口的协议簇。当一个新的连接建立时,服务器端也可以调用getsockname来获取分配给此连接的本地IP地址;当服务器端的一个子进程调用函数exec启动执行时,只能调用getpeername来获取客户端IP地址和端口号。

名字地址转换成数字地址

函数:struct hostent *gethostbyname(const char *hastname);

头文件:netdb.h

说明:函数返回成功返回hostent指针,失败返回空指针,并设置h_errno的值。其中hostent的结构如下:

struct hostent{

       char *h_name;//主机的规范化名字;

       char **h_aliases;//足迹的别名列表;

       char h_addrtype;//返回主机地址类型(ipv4,ipv6)

       char h_length;//返回地址长度(以字节为单位) 

char **h_addr_list;// 主机的一组网络地址列表,使用网络字节序

};

数字地址转化成名字地址

函数:struct hostent *gethostbyaddr(const void *addr,socklet_t len,int type);

头文件:netdb.h

说明:addr为一个含有地址结构(in_addr或in_addr6)的指针,len为该结构的大小,IPV4为4,IPV6为6,type为协议簇。

获取当前主机名字

函数:uname(struct utsname *name);

头文件:sys/utsname.h

说明:返回当前主机的名字,常和gethostbyname一起使用来确定本地主机的IP地址。返回值大于等于0为成功,如果为-1表示失败。Struct ustname结构如下:

struct utsname{

       char sysname[];

       char nodename[];

        char release[];

       char version[];

       char machine[];

       #ifdef  _GUN_SOURCE

       char domainname[];

    #endif

};

服务器名转换成端口号

函数:struct servent *getservbyname(const char *name,const char *proto);

头文件:netdb.h

说明:实现将服务器名转换成端口号的功能,返回非空指针表示成功,否则为失败,serv为服务器名,proto为协议名,可以为空,其中servent定义如下:

struct servent{

    char *s_name;//规范服务器名

    char *s_aliases;//别名成员列表

    int s_port;//端口号

    char *s_proto;//函数调用时指定的协议名

}

端口号转换成服务器名

函数:struct servant *getservbyport(int port,const char* proto);

头文件:netdb.h

说明:实现从端口号到服务器名的转换,返回结果为空指针表示成功,否则失败,port为网络字节序,proto为协议名。

你可能感兴趣的:(编程,网络,struct,服务器,存储,linux内核)