C語言socket編程<一>socket之Winsock API


參考網址:https://blog.csdn.net/Datura_Metel/article/details/79900395

https://www.2cto.com/kf/201804/736240.html

https://blog.csdn.net/m0_37947204/article/details/80489431

https://blog.csdn.net/jinmie0193/article/details/78951055

哈工大相關課程ppt

小弟我學識淺薄,理解不到位之處請各位海涵,另請大哥提點提點!小弟我感激不盡!

目標是一篇搞懂socket編程的所有api,一篇進行實戰演練。

  首先解決下面幾個問題:

  1.對socket編程的理解:

  也即是:調用一些操作系統提供的api,來與應用進程進行交互。

  1.微軟公司在其操作系統中采用了套接字接口 API ,形成了一個稍有不同的 API,並稱之為   Windows Socket Interface,WINSOCK。 

  2.Berkeley UNIX 操作系統定義了一種 API,稱為 套接字接口(socket interface),簡稱套接字( socket)。 

  3.AT&T 為其 UNIX 系統 V 定義了一種 API,簡寫 為 TLI (Transport Layer Interface)。

  這里使用的是WINSOCK

  如何標識對外的通信端點呢? IP地址+端口號 

  操作系統/進程如何管理套接字(對內)?套接字描述符(socket descriptor)是一個小整數 。

  

   類似於文件的抽象

  當應用進程創建套接字時,操作系統分配一個數據結構存儲該套接字相關信息

  返回套接字描述符 

  使用TCP/IP協議簇的網絡應用程序聲明端點地址變量時,使用結構 sockaddr_in.

  定義結構sockaddr_in:

/*
* Socket address, internet style.
*/
struct sockaddr_in {
        short   sin_family;/*地址族(TCP/IP:AF_INET) */ 
        u_short sin_port;/*端口號   */  
        struct  in_addr sin_addr;/*IP地址   */ 
        char    sin_zero[8];/*未用(置0)   */ 
};

  

 

WSAStartup 

使用Socket的應用程序在使用Socket之前必須首先調用 WSAStartup函數 

兩個參數:

 第一個參數指明程序請求使用的WinSock版本,其中高位字節指明副版本、低位字節指明主版本.

  十六進制整數,例如0x102表示2.1版

第二個參數返回實際的WinSock的版本信息

  • 指向WSADATA結構的指針 

示例代碼如下:使用2.1版本的WinSock的程序代碼段 :

wVersionRequested = MAKEWORD( 2, 1 );  //創建字,高字節是2,低字節是1,表示版本2.1
err = WSAStartup( wVersionRequested, &wsaData ); //返回實際的WinSock的版本信息

 

WSACleanup 

 

  應用程序在完成對請求的Socket庫的使用, 最后要調用WSACleanup函數解除與Socket庫的綁定並釋放Socket庫所占用的系統資源 

  不清理的話,在運行codeblocks的時候,常常可能會發生id.exe被占用錯誤。無法運行,需要去管理器找進程關掉才可以繼續運行。

  此類型錯誤處理辦法詳見我其他博文。

 

socket

 

  創建套接字,操作系統返回套接字描述符(sd)

  第一個參數(協議族): protofamily = PF_INET(TCP/IP)

  第二個參數(套接字類型): 

   type = SOCK_STREAM,SOCK_DGRAM or SOCK_RAW(TCP/IP)

  第三個參數(協議號):0為默認

  例:創建一個流套接字的代碼段 

struct protoent *p; 
 p=getprotobyname("tcp");  
SOCKET sd=socket(PF_INET,SOCK_STREAM,p->p_proto);  

TCP:可靠、面向連接、字節流傳輸、點對點

UDP:不可靠、無連接、數據報傳輸 

 

Closesocket  

注意c語言中,如果你不管的話,就會一直保留着資源。。

關閉一個描述符為sd的套接字

如果多個進程共享一個套接字,調用closesocket 將套接字引用計數減1,減至0才關閉

一個進程中的多線程對一個套接字的使用無計數

如果進程中的一個線程調用closesocket將一個套接字 關閉,該進程中的其他線程也將不能訪問該套接字

返回值:

0:成功 

SOCKET_ERROR:失敗

 

bind 

 

綁定套接字的本地端點地址 

IP地址+端口號

參數:

套接字描述符(sd)

端點地址(localaddr) • 結構sockaddr_in   

客戶程序一般不必調用bind函數

服務器端?

 熟知端口號:

 IP地址? 地址通配符:INADDR_ANY

參考網站:https://www.cnblogs.com/ok-lanyan/articles/2634242.html

http://blog.chinaunix.net/uid-23193900-id-3199173.html

   有連接的socket客戶端通過調用Connect函數在socket數據結構中保存本地和遠端信息,無須調用bind(),因為這種情況下只需知道目的機器的IP地址,而客戶通過哪個端口與服務器建立連接並不需要關心,socket執行體為你的程序自動選擇一個未被占用的端口,並通知你的程序數據什么時候打開端口。

  1.需要在建連前就知道端口的話,需要 bind
  2.需要通過指定的端口來通訊的話,需要 bind 

  本來用的是TCP,客戶端就不用綁定端口了,綁定之后只能運行一個client的程序屬於自己人為設定的障礙,而從服務器那邊得到的客戶機連接端口號(是系統自動分配的)與這邊客戶機綁定的端口號根本是不相關的,所以客戶端綁定也就失去了意義。

  如果bind了,就綁定了服務器的端口,也就導致了綁定之后只能運行一個client的程序。

 

listen  

  置服務器端的流套接字處於監聽狀態

    僅服務器端調用 

    僅用於面向連接的流套接字

設置連接請求隊列大小(queuesize)

返回值: 

   0:成功 

   SOCKET_ERROR:失敗 

 

connect

客戶程序調用connect函數來使客戶套接字(sd)與特定計算機 的特定端口(saddr)的套接字(服務)進行連接

 僅用於客戶端

 可用於TCP客戶端也可以用於 UDP客戶端

 TCP客戶端:建立TCP連接

 UDP客戶端:指定服務器端點地址

 

 

accept

 服務程序調用accept函數從 處於監聽狀態的流套接字sd 的客戶連接請求隊列中取出排在最前的一個客戶請求, 並且創建一個新的套接字來與客戶套接字創建連接通道

 僅用於TCP套接字

 僅用於服務器

 利用新創建的套接字 (newsock)與客戶通信

 

send, sendto 

send函數TCP套接字(客戶與服務器)調用了 connect函數的UDP客戶端套接字

  假如調用了connect了,自然就知道了特定端口套接字了,無需再聲明destaddr了。

 

sendto函數用於UDP服務器端套接字未調用 connect函數的UDP客戶端套接字

   假如沒有調用connect,自然就不知道特定端口套接字,需要聲明destaddr,addrlen!!!

 

我們這里需要指出一點:

  由於UDP是無連接的,你使用connect()進行了連接,他也只是發一個:/*我要開始連接了!*/給服務器,然后就開始自顧自地用sendto()或者send()發自己地請求。connect()中,調用TCP返回成功是真的建立了連接,但是UDP並不一定真正建立了連接!!!!

  UDP就像一個任性的人,他說,我要開始做某事了,於是就不論他人是否合作,自己干了起來。

 

recv, recvfrom 

 

recv函數從TCP連接的另一端接收數據,或者從調用了connect函數的UDP客戶端套接字接收服務 器發來的數據

假如調用了connect了,自然就知道了特定端口套接字了,無需再聲明destaddr了。

 

recvfrom函數用於從UDP服務器端套接字與未調 用connect函數的UDP客戶端套接字接收對端數據

 類似同上。

 

setsockopt, getsockopt 

 

setsockopt()函數用來設置套接字sd的選項參數

getsockopt()函數用於獲取任意類型、任意狀態套 接口的選項當前值,並把結果存入optval

 

 

小結:

 

 

 

 

一個容易忽略的問題:進行網絡傳輸機器兩端的“大端機器”和“小端機器“的處理:

 

網絡應用的Socket API(TCP)調用基本流程 

 

 到這里,主要使用的API就說完了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM