VC TCP Socket程式設計

2022-03-23 03:17:50 字數 3563 閱讀 2920

sockets(套接字)程式設計有三種,流式套接字(sock_stream),資料報套接字(sock_dgram),原始套接字(sock_raw);基於tcp的socket程式設計是採用的流式套接字。在這個程式中,將兩個工程新增到乙個工作區。要鏈結乙個ws2_32.lib的庫檔案。

伺服器端程式設計的步驟:

1:載入套接字型檔,建立套接字(wsastartup()/socket());

2:繫結套接字到乙個ip位址和乙個埠上(bind());

3:將套接字設定為監聽模式等待連線請求(listen());

4:請求到來後,接受連線請求,返回乙個新的對應於此次連線的套接字(accept());

5:用返回的套接字和客戶端進行通訊(send()/recv());

6:返回,等待另一連線請求;

7:關閉套接字,關閉載入的套接字型檔(closesocket()/wsacleanup())。

客戶端程式設計的步驟:

1:載入套接字型檔,建立套接字(wsastartup()/socket());

2:向伺服器發出連線請求(connect());

3:和伺服器端進行通訊(send()/recv());

4:關閉套接字,關閉載入的套接字型檔(closesocket()/wsacleanup())。

函式介紹:

1.#include

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

返回值,成功為非負整數,成為套介面描數字;出錯為-1、

family引數:

af_inet --ipv4;

af_inet6--ipv6;

af_local--unix域協議;

af_route--路由socket;

af_key--金鑰socket;

type引數:

sock_stream--位元組流套介面

sock_dgram--資料報套介面

sock_ram--原始套介面

protocal引數一般置為0,當type為sock_ram時不同

2.#include

int connect (int sockfd, const struct sockaddr* servaddr, socklen_t addlen);

返回值,0-成功;-1-出錯;

servaddr引數可以為sockaddr_in和sockaddr_in6型別,但是都必須強制轉化為sockaddr指標型別;

connect函式的出錯處理:

(1)etimeout-connection timed out 目的主機不存在,沒有返回任何相應,例如主機關閉

(2)econnrefused-connection refused(硬錯)到達目的主機後,由於各種原因建立不了連線,主機返回rst(復位)響應,例如主機監聽程序未啟用,tcp取消連線等

(3)ehosttunreach-no route to host(軟錯)路由上引發了乙個目的地不可達的icmp錯誤

其中(1)(3),客戶端會進行定時多次重試,一定次數後才返回錯誤。另外,當connect連線失敗時,sockfd套介面不可用,必須關閉後重新socket分配才行。

3.#include

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

bind函式為套介面分配乙個本地位址和埠

對於tcp協議,本地ip和埠可以不指定,主機會自動分配!

一般來說,我們會給伺服器指定乙個監聽位址結構,以讓客戶端可以建立連線;連線建立後再分配乙個臨時埠作為資料傳輸通道。

而對於客戶端來說,一般不bind本地位址,而是讓核心根據輸出協議自動選定本地ip和埠。

當ip位址和埠設定為萬用字元時,表示由核心自動分配:

(1)對於埠,設定為0表示萬用字元

(2)ip位址,對於ipv4,萬用字元表示如下:

struct sockaddr_in scr;

scr.sin_addr.s_addr=htonl (inaddr_any);

對於ipv6,萬用字元表示如下:

struct sockaddr_in6 scr;

scr.sin6_addr=in6addr_any;

4.#include

int listen (int sockfd, int backlog);

backlog為最大連線個數,包括正在建立的連線和已經建立但是還未進行accept函式的連線,即處於三次握手機制和accept函式之間。

listen函式將sockfd套介面由主動模式變成被動監聽模式,使核心能接受指向此套介面的連線請求 。

當佇列已滿時,伺服器不會對新來的syn有任何回應(包括rst),從而使得客戶端延時重發syn。

5.#include

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

成功,返回非負描數字,稱為已連線套介面;-1表示出錯

sockfd為listen函式後的監聽套介面;

addr和len引數都為 值-結果 引數;

addr返回客戶程序的協議位址,功能類似getpeername函式

len引數呼叫前是addr的長度,返回後是核心讀取的addr結構的準確位元組數。

如果對客戶程序不感興趣,addr`len可設為null;

accept函式返回乙個由核心自動生成的新描述字,稱為 已連線套介面;

一般來說,sockfd稱為監聽套介面,在伺服器程序一直存在;accept返回的已連線套介面,在伺服器子程序中存在,一旦子程序連線結束,此套介面也關閉。

6.通常的處理,伺服器當程序accept後,會fork乙個子程序,同時,父程序關閉已連線套介面,子程序關閉監聽套介面,這樣2個程序就能各司其職:父程序繼續監聽,子程序完成連線操作。

connfd=accept(sockfd,...,...);

if (fork()==0)

close(connfd);//父程序

7。我們可以通過getsockname函式來獲得套介面的本地ip資訊,通過getpeername函式來獲得連線另外一端的ip資訊。

#include

int getsockname (int sockfd, struct sockaddr *addr, socklen_t *len);

得到套介面關聯的本地位址結構

int getpeername (int sockfd, struct sockaddr *addr, socklen_t *len);

得到遠端協議位址結構   len為struct sockaddr的長度

當中的sockfd必須是已連線套介面,不能是監聽套介面。

8.int close (int sockfd);

close只是減少某個套介面的計數,只有當計數為0時,核心才會向對方主機傳送fin。。。

如果確實需要傳送fin,那可以使用shutdown函式

int shutdown(int sockfd, int flags);

flags為shut_wr,  shut_rd,  shut_rdwr..關閉套介面的相應功能,(讀,寫),並傳送fin,不管計數是否為0。

程式設計,還是程式設計

喜歡程式設計,雖然水平一般,但還是執著地學習與程式設計有關的知識。中間因為工作關係與程式設計遠離了一段時間,現在又重拾起來,細想起來還是因為喜歡吧。喜歡程式軟體的思想和原理,喜歡程式 的魅力和成就感。程式設計軟體的思想是最值得學習的,一直認為思想決定行動,思想改變世界。每種軟體的流行和受人追捧,無不...

少兒程式設計程式設計

機械人比賽,聽上去讓人有一種高大上的科技感,沒錯,在大多數人眼裡,玩機械人那是科學家做的事情,不過隨著機械人教育的普及,越來越多的孩子也能夠駕馭這高大上的機械人。格物斯坦小坦克告訴你原因,這是歸結於孩子對於程式設計課程的學習,學會對機械人進行程式設計了,自然就能玩轉機械人啦。參加機械人比賽的意義遠遠...

LINUX程式設計 socket程式設計

什麼是套接字 套接字是一種通訊過程,它使客戶 伺服器系統的開發工作既可以在本地單機上進行,也可以跨網路進行。套接字建立過程 1,建立乙個套接字,這是分配給該伺服器程序的乙個作業系統資源,套接字由伺服器通過系統呼叫socket建立出來的,所以其它程序將不能對它進行訪問。2,給套接字起個名字,用系統呼叫...