1. 程式人生 > >套接字程式設計簡介(筆記)

套接字程式設計簡介(筆記)

July 25, 2015 8:26 PM

前言

網路程式設計->套接字->套接字地址結構。
套接字地址結構可以在兩個方向上傳遞:從程序到核心、從核心到程序!

套接字結構

以Windows作為例項,看看套接字的結構:

/*
 * Socket address, internet style.
 */
struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

注意:
套接字地址結構僅在給定主機上使用,雖然結構中的某些欄位(例如IP地址和埠號)用在不用主機之間的通訊中,但是結構本身並不在主機之間傳遞!

**
當作為一個引數傳遞進任何套接字函式時,套接字地址結構總是以引用形式(也就是以指向該結構的指標)來傳遞,然而以這樣的指標作為引數之一的任何套接字函式必須處理來自所支援的任何協議族的套接字地址結構
在如何宣告所傳遞指標的資料型別上存在一個問題?
解決的方法:定義一個通用的套接字資料結構!

Ret = bind(ServerSocket, (struct sockaddr*)&LocalAddr, sizeof(LocalAddr));

**


圖一 套接字結構圖!

套接字傳遞方向

從程序空間到核心空間 從核心空間到程序空間
函式 bind 、connect 、sendto
圖示

操作套接字結構的函式

使用inet_addr函式(返回值為32位的網路位元組序二進位制值)易於出現的問題:
1.所有的2^3個可能的二進位制都是有效的IP地址(0.0.0.0到255.255.255.255),但是當出錯時該函式返回INADDR_NONE常值(通常是一個32位均為1的值),這意味著點分十進位制數(255.255.255.255)不能由該函式處理。因為其的二進位制值被用於指示函式失敗。

改用inet_aton函式!

對結果進行靜態儲存導致該函式不可重入且非執行緒安全!!!!!!!!

ssize_t Readn(int fd, void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nread;
    char *ptr;

    ptr = vptr;
    nleft = n;
    while( nleft > 0 )
    {
         if( ( nread = read(fd,ptr,nleft ) ) < 0 )
         {
              if( errno == EINTR )
                  nread = 0;
              else
                  return -1;
         }
         else if( nread == 0 )
              break;

         nleft -= nread;
         ptr += nread;
    }
    return ( n - nleft );
}

套接字地址結構是每一個網路程式的重要組成部分,分配它們,填寫它們,把指向它們的指標傳遞給各個套接字函式。

TCP套接字為應用程序提供一個位元組流,它們沒有記錄標記,從TCP套接字read的返回值可能比我們請求的數量少,但是這不表示發生錯誤。對於文字行互動的應用來說,程式應該按照操作緩衝區而非按照操作文字行來編寫。

基本TCP套接字程式設計

下圖給出TCP客戶端和服務段程序之間發生的一些典型事件的時間表!

注意:
1.客戶在呼叫connect前不必非得呼叫bind函式,因為如果需要的話,核心會確定源IP地址,big選擇一個臨時埠作為源埠。

2、按照TCP狀態轉換圖(圖2-4 原書中!),connect函式導致當前套接字從CLOSED狀態(該套接字自從由socket函式建立以來一直所處的狀態)轉移到SYN_SENT狀態,若成功再轉移到ESTABLISHED狀態,若connect失敗則該套接字不再可用,必須關閉,我們不能對這樣的套接字再次呼叫connect函式。

可以通過使用GetEnv函式獲取環境變數,來改變程式執行軌跡!!!!!!!!

併發伺服器的程式設計框架

pid_t pid
int listenfd, connfd
listenfd = socket();
Bind(listenfd,...)
for(;;)
{
    connfd = Accept(listenfd,...)
    if( ( pid = for() ) == 0 )
    {
        close(linsenfd);
        doit(connfd);
        close(connfd);
    }
    close(connfd);
}