基础知识:
 
套接口结构:
头文件<netinet/in.h>
struct in_addr{
         in_addr_t s_addr;    /* 32 bit Ipv4 address ,network byte ordered */
}
struct sockaddr_in{
         uint8_t sin_len;        /* length of structure */
         sa_family_t sin_family; /* AF_INET */
         in_port_t sin_port; /* 16_bit TCP or UDP port number,network byte ordered */
         struct in_addr sin_addr; /* 32-bit Ipv4 address , network byte ordered*/
         char sin_zero[8];      /* unused */
};
Ipv4 地址和TCP或UDP端口号在套接口结构中是以网络字节序来存储。
 
通用套接口地址结构:
当作为参数传递给任一个套接口函数时,套接口地质结构总是通过指针来传递,但是通过指针来取得此参数的套接口函数必须处理来自所支持的任何协议簇的套接口地址结构。于是套接口函数被定义为采用指向通用套接口地址结构的指针;在<sys/socket.h>头文件中定义一个通用的套接口地址结构:
         struct sockaddr{
                   uint8_t sa_len;
                   sa_family_t sa_family; /* address family: AF_xxx value */
                   char sa_data[14];    /* protocol-specific address */
};
这就要求对套接口函数的调用都必须将指向特定于协议的套接口地址结构的指针类型转换成指向通用套接口地址接口的指针,例如:
         struct sockaddr_in serv;
         bind(sockfd,(struct sockaddr *)&serv,sizeof(serv));
从进程到内核传递套接口地址结构有3个函数:bind,connect和sendto,这3个函数的一个参数是指向套接口地址结构的指针,另一个参数是结构的整数大小,例如:
strcut sockaddr_in serv;
connect (sockfd ,(SA *)serv,sizeof(serv));
 
从内核到进程传递套接口地址结构有4个函数:accept,recvfrom,getsockname和getpeername。这4个函数的两个参数是:指向套接口地址结构的指针和指向表示结构大小的整数的指针,例如:
         struct sockaddr_un cli;
         socklen_t len;
         len = sizeof(cli);
         getpeername(unixfd,(SA * )&cli,&len);
将长度以指针的形式传给内核是告诉内核结构的大小,不至于处理越界,当函数返回时,结构大小又是另外一个结果(这个结构中确切存储了多少信息)。
字节排序函数和地址转换函数:
字节排序函数:
头文件 <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);
 
地址转换函数:
头文件: <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将strptr所指的C字符串转换成32位的网络字节序二进制值,并通过指针addrptr来存储。
inet_addr 进行相同的转换,返回值为32位网络字节序二进制值。这个函数存在这样的问题:所以2³²个可能的二进制值都是有效的IP地址(从0.0.0.0到255.255.255.255),但当出错时返回一个常值INADDR_NONE(一般为一个32位均为1的值)。这意味着点分十进制数串255.255.255.255不能由此函数处理,因为它的二进制值被用来指示函数失败。
 
 
套接口TCP编程:
执行一个网络I/O,首先需要调用socket函数来创建一个套接字。
头文件: <socket.h>
int socket(int family,int type,int protocol);
参数family为协议簇,参数type为套接类型,

      
    解释
AF_INET
AF_INET6
AF_LOCAL
AF_ROUTE
AF_KEY
Ipv4协议
Ipv6协议
Unix域协议
路由套接口
密钥套接口

                  
 
 
 
 
 
 

Socket函数协议簇常值
                        

                           
 

      类型
      解释
SOCK_STREAM
SOCK_DGRAM
SOCK_RAM
字节流套接口
数据报套接口
原始套接口

Socket函数的套接口类型
        

                          

                                  AF_INET            AF_INET6     AF_LOCAL  AF_ROUTE  AF_KEY

 TCP
 TCP
   Yes
 
 
 UDP
 UDP
   Yes
 
 
 IPV4
 Ipv6
 
   Yes
 Yes

SOCK_STREAM
SOCK_DGRAM
SOCK_RAM

                                        SOCKET 函数的簇与类型组合

TCP客户用connect函数来建立一个与TCP服务器的链接
int connect(int sockfd,const struct sockaddr *servaddr,socklen_t addrlen);
函数connect 激发TCP的三路握手过程,且仅在连接建立成功或出错时才返回。
 
服务器启动时,要捆绑众所周知端口,bind函数
头文件: <sys/socket.h>
int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
 
通配地址常值INADDR_ANY来指定,其值一般为0,它通知内核选择IP地址。
 
listen函数
函数listen 仅被TCP服务器调用,它做两件事件:
1.       当函数socket创建一个套接口时,它被假设为一个主动套接口,也就是说,它是一个将调用connect发起连接的客户套接口,函数listen将未连接的套接口转换成被动套接口,指示内核应接受指向此套接口的连接请求,
2.       函数的第二个函数规定了内核为此套接口排队的最大连接个数
int listen(int sockfd,int backlog);
 
TCP服务器调用accept,从已完成连接队列头返回下一个已完成连接,若已完成队列为空,则进程睡眠。
int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);
参数cliaddr和addrlen用来返回连接对方进程的协议地址。