基本TCP套接字程式設計API

weixin_34253539發表於2018-09-22
套接字地址結構:
#include<netinet/in.h>
struct in_addr{           #存放ip地址
    in_addr_t       s_addr;     /*32-bit IPv4 address*/
};                          /*network byte ordered*/
struct sockaddr_in{  #存放sock地址所有資訊,包含ip
    unit8_t     sin_len;        /*length of structure(16)*/
    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];    
  • 通用套接字地址結構是為了解決不同協議族之間套接字地址結構不同的問題
struct sockaddr{
    unit8_t sa_len;     /*address family:AF_xxx value*/
    sa_family_t sa_family;  /*protocol-specific address*/
    char             sa_data[14] ; 
  • 套接字函式都被定義為以指向某個通用套接字地址結構的一個指標作為其引數之一,所以函式的任何呼叫都要進行強制型別轉換,舉例如下
struct sockaddr_in server ;
int bind(int, (struct sockaddr *) &server, sizeof(server));
API:
#include <sys/socket.h>
int socket(int family, int type, int protocol);  
    family:
        AF_INET, AF_INET6, AF_LOCAL(AF_UNIX), AF_ROUTE, AF_KEY
    type:
        SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW
    protocol:
        IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP, 0(default)
    error return -1
 
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen);
    success return 0, error return -1
 
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr * myaddr, socklen_t addrlen);
    success return 0, error return -1
    server:
        IPV4:
            struct sockaddr_in servaddr;
            servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        IPV6:
            struct sockaddr_in6 servaddr;
            servaddr.sin6_addr = in6addr_any;
 
#include <sys/socket.h>
int listen(int sockfd, int backlog);
    success return 0, error return -1
    convert active-socket to passive-socket
 
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen);
    error return -1
    sockfd should be a passive-socket(listened-socket)
 
#include <unistd.h>
pid_t fork(void);
    error return -1
 
#include <unistd.h>
int execl(const char * pathname, const char * arg0, ... /* (char *)0 */);
int execv(const char * pathname, char * const argv[]);
int execle(const char * pathname, const char * arg0, ... 
           /* (char *)0, char * const envp[] */);
int execve(const char * pathname, char * const argv[], char * const envp[]);
int execlp(const char * filename, const char * arg0, ... /* (char *)0 */);
int execvp(const char * filename, char * const argv[]);
    success no return, error return -1
 
#include <unistd.h>
int close(int sockfd);
    success return 0, error return -1
 
#include <sys/socket.h>
 #取得本地套接字地址
int getsockname(int sockfd, struct sockaddr * localaddr, socklen_t * addrlen);
#取得對方套接字地址
int getpeername(int sockfd, struct sockaddr * peeraddr, socklen_t * addrlen); 
    success return 0, error return -1
  • 經過TCP封裝後的資料稱為TCP segment,TCP為通訊雙方維持一個連結,且在核心儲存相關資料,這部分資料包括TCP頭部資訊和TCP核心緩衝區。當應用層呼叫write進行寫資料的時候,資料首先會從使用者空間拷貝到與該TCP連結所對應的核心緩衝區中,然後TCP模組呼叫IP模組進行資料的傳送。
  • 當應用程式多次執行寫操作的時候,TCP把這些資料快取到本地的TCP緩衝區中,當TCP真正開始傳送資料的時候,傳送緩衝區中的這些等待傳送的資料可能被封裝成一個或多個TCPsegment,所以應用程式的寫次數和TCP傳送的次數沒有數量關係。
  • 當接受段接收到一個或多個TCP segment後,TCP把他們攜帶的資料按照TCPsegment的格式進行解析後發到TCP接受緩衝區中,並通知應用程式讀資料(怎麼通知?)。接受端可以一次性全部讀完,也可以讀多次,這取決於應用程式緩衝區的大小。

獲取套接字的地址資訊

#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位二進位制網路位元組序的IPV4地址,否則為INADDR_None
char *inet_ntoa(struct in_addr inaddr);
//返回:指向一個點分十進位制數串的指標

相關文章