Windows Sockets程式設計學習總結

2021-08-20 10:29:10 字數 3932 閱讀 5242

1、windows sockets已經封裝好了具體的實現方法,在這裡不深究它的機制,只是能理解和熟練使用就可以。

2、tcp、udp

sock_stream

即tcp協議,要建立連線,傳送的資料,無差錯,不丟失,不重複,且按序到達。

sock_dgram即

udp協議,不建立連線,會丟包,實時傳輸。

3、網路協議:

pf_inet, af_inet: ipv4    

pf_inet6, af_inet6: ipv6

af_inet 表示 ipv4 位址,例如 127.0.0.1;af_inet6 表示 ipv6 位址,例如 1030::c9b4:ff12:48aa:1a2b

127.0.0.1,它是乙個特殊ip位址,表示本機位址

af 表示address family 位址族

pf 表示protocl family 協議族

winsock2.h中

#define af_inet 0

#define pf_inet af_inet

socket傳遞資料前需要資料封裝,裡面需要af_inet的支援。

4、實現流程:

伺服器:

建立wsadata(儲存接收的資料)  ->  呼叫wsastartup函式  ->  建立socket   ->   填寫ip位址和埠    ->    bind()繫結ip位址和埠(判斷繫結成功)   ->    監聽scoket    ->   傳送和接收資料   ->   斷開連線   ->    關閉

使用dll之前必須把dll載入到當前程式,你可以在編譯時載入,也可以在程式執行時載入

方法1:

#pragma comment (lib, "ws2_32.lib")
方法2:

word wversionrequested;

wversionrequested = makeword( 2, 2 ); // 請求2.2版本的winsock庫

wsastartup是任何使用winsock的應用程式或者dll首先必須呼叫winsock庫函式.一方面它初始化 ws2_32.dll,另一方面他用於在應該程式dll與系統winsock庫版本協商.

4.1、socket()函式 建立socket

intsocket(int af, int type, int protocol);
af:協議域或協議簇。常用af_inet、af_inet6,決定socket的位址型別。

type:指socket型別,sock_stream、sock_dgram,即tcp、udp。

protocol:指定協議,常用的協議有,ipproto_tcp、ipptoto_udp、ipproto_sctp、ipproto_tipc等,它們分別對應tcp傳輸協議、udp傳輸協議、stcp傳輸協議、tipc傳輸協議,但是大部分設為0即可,會自動匹配。

return:返回乙個檔案的描述符,為int型,成功返回生成的socket,失敗返回invalid_socket

4.2、 bind() 繫結socket

int bind(socket sock, const struct sockaddr *addr, int addrlen);
sock:是socket的檔案描述符,addr是sockaddr結構體變數的指標,addlen是addr變數的大小,可由sizeof()計算

4.3、 connect()  連線socket

int connect(socket sock, const struct sockaddr *serv_addr, int addrlen);
引數跟bind()一致

4.4、listen() 監聽socket

int

listen

(socket

sock,

int backlog);

sock 為需要進入監聽狀態的套接字,backlog 為請求佇列的最大長度

緩衝區的長度(能存放多少個客戶端請求)可以通過 listen() 函式的 backlog 引數指定,但究竟為多少並沒有什麼標準,可以根據你的需求來定,併發量小的話可以是10或者20。

如果將 backlog 的值設定為 somaxconn,就由系統來決定請求佇列長度,這個值一般比較大,可能是幾百,或者更多。

當請求佇列滿時,就不再接收新的請求,對於 linux,客戶端會收到 econnrefused 錯誤,對於 windows,客戶端會收到 wsaeconnrefused 錯誤。

注意:listen() 只是讓套接字處於監聽狀態,並沒有接收請求。接收請求需要使用 accept() 函式。

4.4、 accept() 接收socket

socket

accept

(socket

sock,

struct

sockaddr

*addr,

int*addrlen);

它的引數與 listen() 和 connect() 是相同的:sock 為伺服器端套接字,addr 為 sockaddr_in 結構體變數,addrlen 為引數 addr 的長度,可由 sizeof() 求得。

accept() 返回乙個新的套接字來和客戶端通訊,addr 儲存了客戶端的ip位址和埠號,而 sock 是伺服器端的套接字,大家注意區分。後面和客戶端通訊時,要使用這個新生成的套接字,而不是原來伺服器端的套接字。

最後需要說明的是:listen() 只是讓套接字進入監聽狀態,並沒有真正接收客戶端請求,listen() 後面的**會繼續執行,直到遇到 accept()。accept() 會阻塞程式執行(後面**不能被執行),直到有新的請求到來。

4.5、send()和recv()

從伺服器端傳送資料使用 send() 函式,它的原型為:

int send(socket sock, const char *buf, int len, int flags);
sock 為要傳送資料的套接字,buf 為要傳送的資料的緩衝區位址,len 為要傳送的資料的位元組數,flags 為傳送資料時的選項。

返回值和前三個引數不再贅述,最後的 flags 引數一般設定為 0 或 null,初學者不必深究。

在客戶端接收資料使用 recv() 函式,它的原型為:

int recv(socket sock, char *buf, int len, int flags);
4.6、返回值

socket()  accept()

如果成功就返回生成的socket,如果失敗就返回invalid_socket.

#define invalid_socket  (socket)(~0)

實際上是 0xffffffff 4bytes

bind() listen() connect()

如果成功就返回0,如果失敗就返回socket_error,需要通過wsagetlasterror獲得進一步的錯誤資訊.

#define socket_error            (-1)

實際上是 0xffffffff 4bytes

send() sendto()

如果成功就返回傳送的位元組數,如果失敗就返回socket_error,需要通過wsagetlasterror獲得進一步的錯誤資訊.

recv() recvfrom()

如果成功就返**到的位元組數,如果如果失敗就返回socket_error,需要通過wsagetlasterror獲得進一步的錯誤資訊.

如果連線被溫和的關閉,返回0,但是recvfrom通常是用於無連線的udp socket.

靜態聯編與動態聯編

在c 中,多型性主要是通過函式過載實現的。過載函式是指程式中對同名函式進行呼叫時,編譯器會根據函式引數的型別和個數,決定該呼叫哪一段函式 來處理這個函式呼叫。這種把函式呼叫與適當的函式 相對應的動作,叫做聯編。聯編分為靜態聯編和動態聯編。在編譯階段決定執行哪個同名的被呼叫函式,稱為靜態聯編。在編譯階...

靜態聯編和動態聯編

聯編是指乙個電腦程式自身彼此關聯 使乙個 源程式經過編譯 連線,成為乙個可執行程式 的過程,在這個聯編過程中,需要確定程式中的操作呼叫 函式呼叫 與執行該操作 函式 的 段之間的對映關係,按照聯編所進行的階段不同,可分為靜態聯編和動態聯編。靜態聯編 呼叫函式和被調函式在程式編譯時,他們在記憶體中的位...

靜態聯編和動態聯編

聯編就是將模組或者函式合併在一起生成可執行 的處理過程,同時對每個模組或者函式呼叫分配記憶體位址,並且對外部訪問也分配正確的記憶體位址,它是電腦程式彼此關聯的過程。按照聯編所進行的階段不同,可分為兩種不同的聯編方法 靜態聯編和動態聯編。靜態聯編是指在編譯階段就將函式實現和函式呼叫關聯起來,因此靜態聯...