網路程式設計學習筆記 socket程式設計

2021-10-06 06:12:58 字數 4125 閱讀 7002

本地的程序間通訊(ipc)有很多種方式,總結為4類:

在本地可以通過程序pid來唯一標識乙個程序,但是在網路中這是不可以的。tcp/ip協議族幫我們解決了這個問題,網路層的「ip位址」可以唯一標識網路中的主機,而傳輸層的「協議+埠」可以唯一標識主機中的應用程式(程序)。這樣利用三元組(ip位址、協議、埠)就可以標識網路的程序了。

使用tcp/ip協議的應用程式通常採用應用程式設計介面:unix bsd的套接字(socket)和unix system v的tli(已被淘汰),來實現網路程序之間的通訊。

socket起源於unix,而unix/linux基本哲學之一就是「一切皆檔案」,都可以用「開啟open->讀寫write/read->關閉close」模式來操作。socket就是該模式的乙個實現,是一種特殊的檔案,一些socket函式就是對其進行的操作(讀寫io,開啟,關閉)。

int socket(int domain, int type, int protocol);

socket函式對應於普通檔案的開啟操作。普通檔案的開啟操作返回乙個檔案描述字,而socket()用於建立乙個socket描述符,它唯一標識乙個socket。

bind()函式把乙個位址族中的特定位址賦給socket。例如對應af_inet、af_inet6就是把乙個ipv4或ipv6位址和埠號組合賦給socket。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

ipv4:

struct sockaddr_in ;

/* internet address. */

struct in_addr ;

ipv6對應的是:

struct sockaddr_in6 ;

struct in6_addr ;

主機位元組序就是我們平常說的大端和小端模式:不同的cpu有不同的位元組序型別,這些位元組序是指整數在記憶體中儲存的順序,這個叫做主機序。

小端:低位位元組放在記憶體的低位址端,高位位元組放在記憶體的高位址端。

大端:高位位元組放在記憶體的低位址端,低位位元組放在記憶體的高位址端。

網路位元組序:4個位元組的32bit值以下面的次序傳輸:首先是0-7bit,其次是8-15bit,然後16-23bit,最後是24-31bit。這種傳輸次序稱作大端位元組序。由於tcp/ip首部中所有的二進位制整數在網路中傳輸時都要求以這種次序,因此它又稱作網路位元組序。

所以,在將乙個位址繫結到socket的時候,請先將主機位元組序轉換成網路位元組序,而不要假定主機位元組序跟網路位元組序一樣使用的是大端。

如果作為乙個伺服器,在呼叫socket(),bind()之後就會呼叫listen()來監聽這個socket,如果客戶端這時呼叫connect()發出連線請求,伺服器端就會接收到這個請求。

socket()函式建立的socket預設是乙個主動型別的,listen函式將socket變為被動型別的,等待客戶的連線請求。

int listen(int sockfd, int backlog);

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

tcp伺服器端依次呼叫socket、bind、listen之後,就會監聽指定的socket位址了。tcp客戶端依次呼叫socket、connect之後就像tcp伺服器傳送了乙個連線請求。tcp伺服器監聽到這個請求之後,就會呼叫accept函式去接收請求,這樣連線就建立好了。之後就可以開始網路i/o操作了,即類同於普通檔案的讀寫i/o操作。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

網路i/o操作有以下幾組:

在伺服器與客戶端建立連線之後,會進行一些讀寫操作,完成了讀寫操作就要關閉相應的socket描述字。

#include

int close(int fd);

close乙個tcp socket的預設行為是把該socket標記為已關閉,然後立即返回到呼叫程序。該描述字不能再由呼叫程序使用,也就是說不能再作為read或write的第乙個引數。

注意:close操作只是相應socket描述字的引用計數-1。只有當引用計數為0的時候,才會觸發tcp客戶端向伺服器傳送終止連線請求。

客戶端向伺服器傳送乙個syn j

伺服器向客戶端響應乙個syn k,並對syn j進行確認ack j+1

客戶端再向伺服器發乙個確認ack k+1

從圖中可以看出來,當客戶端呼叫connect時,觸發了連線請求,向伺服器傳送了syn j包,這時connect進入阻塞狀態;伺服器監聽到連線請求,即收到syn j包,呼叫accept函式接收請求向客戶端傳送syn k, ack j+1,這時accept進入阻塞狀態;客戶端收到伺服器的syn k, ack j+1之後,這時connect返回,並對syn k進行確認;伺服器收到ack k+1時,accept返回。

某個應用程序首先呼叫close主動關閉連線,這時tcp傳送乙個fin m;

另一端接收到fin m之後,執行被動關閉,對這個fin進行確認。

一段時間之後,接收到檔案結束符的應用程序呼叫close關閉它的socket。也會傳送乙個fin n;

接收到這個fin的源傳送端tcp對它進行確認。

伺服器端**:

#include#include#include#include#include#include#include#define maxline 4096

int main(int argc, char** ar**)

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = af_inet;

servaddr.sin_addr.s_addr = htonl(inaddr_any);

servaddr.sin_port = htons(6666);

if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)

if( listen(listenfd, 10) == -1)

printf("*****=waiting for client's request*****=\n");

while(1)

n = recv(connfd, buff, maxline, 0);

buff[n] = '\0';

printf("recv msg from client: %s\n", buff);

close(connfd);

}close(listenfd);

}

客戶端**:

#include#include#include#include#include#include#include#define maxline 4096

int main(int argc, char** ar**)

if( (sockfd = socket(af_inet, sock_stream, 0)) < 0)

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = af_inet;

servaddr.sin_port = htons(6666);

if( inet_pton(af_inet, ar**[1], &servaddr.sin_addr) <= 0)

if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

printf("send msg to server: \n");

fgets(sendline, 4096, stdin);

if( send(sockfd, sendline, strlen(sendline), 0) < 0)

close(sockfd);

exit(0);

}

socket網路程式設計 學習筆記

伺服器端先初始化socket,然後與埠繫結 bind 對埠進行監聽 listen 呼叫accept阻塞,等待客戶端連線。在這時如果有個客戶端初始化乙個socket,然後連線伺服器 connect 如果連線成功,這時客戶端與伺服器端的連線就建立了。客戶端傳送資料請求,伺服器端接收請求並處理請求,然後把...

android學習筆記 Socket編

android學習筆記 socket程式設計 inonoclas 十三 socket程式設計 socket基本通訊模型 使用基於tcp協議的socket 使用基於udp協議的socket socket套接字 用於描述ip位址和埠是乙個通訊鏈的控制代碼 以你公用程式通過 套接字 向網路發出請求或者應答...

網路程式設計之SOCKET程式設計學習筆記

使用tcp ip協議的應用程式通常採用應用程式設計介面 unix bsd的套接字 socket 和unix system v的tli 已經被淘汰 來實現網路程序之間的通訊。就目前而言,幾乎所有的應用程式都是採用socket,而現在又是網路時代,網路中程序通訊是無處不在,這就是我為什麼說 一切皆soc...