2009年2月4日 星期三

socket - tcp - 觀念

程式寫出來了,觀念還是要說一下,tcp實作檔案傳輸請到這裡

IPv4的定義:
struct in_addr {
  in_addr_t s_addr;
};
struct sockaddr_in{
  unit8_t sin_len;
  sa_family_t sin_family;
  in_port_t sin_port;
  struct in_addr sin_addr;
char sin_zero[8];
};

一般在使用socket通訊時,分身為server的應用程式必需先建立一個通訊端(socket)
再以bind系統呼叫(system call)來完成通訊端的命名
server的應用程式會以listen系統呼叫來建立一個佇列(queue)
再以accept系統呼叫來進行接收
建立好連線之後,通訊端可看做是一個低階的檔案描述子(file descriptor)程式,只要利用read及write指令即可完成雙向的資料通訊

Socket提供了兩種通訊型式
–AF_UNIX
•主要是用來讓單一台電腦內的兩個應用程式,利用標準(或非標準)裝置的埠(PORT)來做資料的傳輸

–AF_INET
•基本的Internet Protocol(IP)的通訊協定,其又可分為stream與datagram等兩層的服務
–Stream是一種可靠的雙向通訊方式,可確保資料的完整性
–Datagram是一種不需要建立連結的通訊方式,無法保證所傳送出資料的完整性

在Linux和Windows網絡編程時需要用到htons和htonl函數,用來將主機字節順序轉換為網絡字節順序。
得到的結果是4096,一開始看感覺很怪。

解釋如下,數字16的16進製表示為0x0010,數字4096的16進製表示為0x1000。由於Intel機器是little-end,存儲數字16時實際順序為1000,存儲4096時實際順序為0010。因此在發送網絡包時為了報文中數據為0010,需要經過htons進行字節轉換。如果用IBM等big-end機器,則沒有這種字節順序轉換,但為了程序的可移植性,也最好用這個函數。

另外用注意,數字所佔位數小於或等於一個byte(8 bits)時,不要用htons轉換。這是因為對於主機來說,big-end and little-end的最小單位為字節(byte)。

sin_family指代協議族,在socket編程中只能是AF_INET
sin_port存儲端口號(使用網絡字節順序)
sin_addr存儲IP地址,使用in_addr這個數據結構
sin_zero是為了讓sockaddr與sockaddr_in兩個數據結構保持大小相同而保留的空字節。
s_addr按照網絡字節順序存儲IP地址
sockaddr_in和sockaddr是並列的結構,指向sockaddr_in的結構體的指針也可以指向
sockadd的結構體,並代替它。也就是說,你可以使用sockaddr_in建立你所需要的信息,
在最後用進行類型轉換就可以了bzero((char*)&mysock,sizeof(mysock));//初始化
mysock結構體名
mysock.sa_family=AF_INET;
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
……
等到要做轉換的時候用:
(struct sockaddr*)mysock
換句話說在設定的時候用sockaddr_in
而在使用的時候用sockaddr
其實sockaddr_in與sockaddr是一樣的東西
我想是因為要相容於之後的版本,所以,在設定的時候用不同的sockaddr_in
而真正在使用的時候,均使用sockaddr,也就是要轉換成sockaddr的指標

詳細資料可以參考我寫的tcp程式碼,我有註釋在裡面!

[2009.04.30 補充]
在同一個ip,應用程式不可以bind同一個port,但是,透過
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &flag, len);
可以決解目前這一個問題,詳情請看
socket編程:SO_REUSEADDR例解 (轉)

參考資料:
結構體sockaddr_in和sockaddr用法的問題
TCP 與 UDP
複製檔案 - fread fwrite
請問int a=send(socket,buf,len,flags) 這個a是代表發送的包的大小嗎?(各個參數值已知的情況下)

沒有留言: