C Socket通訊原理(基礎篇)

2021-08-21 05:48:59 字數 4779 閱讀 8303

這幾天博主花了4天時間去學習,整理socket通訊。大致懂了一點,現在我來總結一下關於c#socket通訊的原理

首先我們要知道網路中的程序是如何進行通訊的

在本地可以通過程序pid來唯一標識乙個程序,但是在網路中這是行不通的。其實tcp/ip協議族已經幫我們解決了這個問題,網路層的「ip位址

可以唯一標識網路中的主機,而

傳輸層的「協議+埠

可以唯一標識主機中的應用程式(程序)。這樣利用三元組(ip位址,協議,埠)就可以標識網路的程序了,網路中的程序通訊就可以利用這個標誌與其它程序進行互動。

什麼是socket? 通俗一點的說法

網路上的兩個程式通過乙個雙向的通訊連線實現資料的交換,這個連線的一端稱為乙個socket。

建立網路通訊連線至少要一對埠號(socket)。socket本質是程式設計介面(api),對tcp/ip的封裝,tcp/ip也要提供可供程式設計師做網路開發所用的介面,這就是socket程式設計介面;http是轎車,提供了封裝或者顯示資料的具體形式;socket是發動機,提供了網路通訊的能力。

socket的英文原義是「孔」或「插座」。作為bsd unix的

程序通訊機制,取後一種意思。通常也稱作"

套接字",用於描述ip位址和埠,是乙個通訊鏈的控制代碼,可以用來實現不同虛擬機器或不同計算機之間的通訊。在internet上的

主機一般執行了多個服務軟體,同時提供幾種服務。每種服務都開啟乙個socket,並繫結到乙個埠上,不同的埠對應於不同的服務。socket正如其英文原義那樣,像乙個多孔插座。一台主機猶如布滿各種插座的房間,每個插座有乙個編號,有的插座提供220伏交流電, 有的提供110伏交流電,有的則提供有線電視節目。 客戶軟體將插頭插到不同編號的插座,就可以得到不同的服務。

socket有關的函式:

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

· domain:即協議域,又稱為協議族(family)。常用的協議族有,

af_inet

、af_inet6

、af_local

(或稱af_unix

,unix域socket)、

af_route

等等。協議族決定了socket的位址型別,在通訊中必須採用對應的位址,如af_inet決定了要用ipv4位址(32位的)與埠號(16位的)的組合、af_unix決定了要用乙個絕對路徑名作為位址。

· type:指定socket型別。常用的socket型別有,

sock_stream

、sock_dgram

、sock_raw

、sock_packet

、sock_seqpacket

等等(socket的型別有哪些?)。

· protocol:故名思意,就是指定協議。常用的協議有,

ipproto_tcp

、ipptoto_udp

、ipproto_sctp

、ipproto_tipc

等,它們分別對應tcp傳輸協議、udp傳輸協議、stcp傳輸協議、tipc傳輸協議(這個協議我將會單獨開篇討論!)。

正如上面所說bind()函式把乙個位址族中的特定位址賦給socket。例如對應

af_inet

、af_inet6

就是把乙個ipv4或ipv6位址和埠號組合賦給socket。

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

sockfd:即socket描述字,它是通過socket()函式建立了,唯一標識乙個socket。bind()函式就是將給這個描述字繫結乙個名字。

通常伺服器在啟動的時候都會繫結乙個眾所周知的位址(如ip位址+埠號),用於提供服務,客戶就可以通過它來接連伺服器;而客戶端就不用指定,有系統自動分配乙個埠號和自身的ip位址組合。這就是為什麼通常伺服器端在listen之前會呼叫bind(),而客戶端就不會呼叫,而是在connect()時由系統隨機生成乙個。

如果作為乙個伺服器,在呼叫

socket()

、bind()

之後就會呼叫

listen()

來監聽這個socket,如果客戶端這時呼叫

connect()

發出連線請求,伺服器端就會接收到這個請求。

int

listen

(int sockfd, int backlog);int

connect

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

listen函式的第乙個引數即為要監聽的socket描述字,第二個引數為相應socket可以排隊的最大連線個數。socket()函式建立的socket預設是乙個主動型別的,listen函式將socket變為被動型別的,等待客戶的連線請求。

connect函式的第乙個引數即為客戶端的socket描述字,第二引數為伺服器的socket位址,第三個引數為socket位址的長度。客戶端通過呼叫connect函式來建立與tcp伺服器的連線。

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);

accept函式的第乙個引數為伺服器的socket描述字,第二個引數為指向struct sockaddr *的指標,用於返回客戶端的協議位址,第三個引數為協議位址的長度。如果accpet成功,那麼其返回值是由核心自動生成的乙個全新的描述字,代表與返回客戶的tcp連線。

注意:accept的第乙個引數為伺服器的socket描述字,是伺服器開始呼叫socket()函式生成的,稱為

監聽socket描述字

;而accept函式返回的是

已連線的socket描述字

。乙個伺服器通常通常僅僅只建立乙個監聽socket描述字,它在該伺服器的生命週期內一直存在。核心為每個由伺服器程序接受的客戶連線建立了乙個已連線socket描述字,當伺服器完成了對某個客戶的服務,相應的已連線socket描述字就被關閉。

萬事具備只欠東風,至此伺服器與客戶已經建立好連線了。可以呼叫網路i/o進行讀寫操作了,即實現了網咯中不同程序之間的通訊!網路i/o操作有下面幾組:

· read()/write()

· recv()/send()

· readv()/writev()

· recvmsg()/sendmsg()

· recvfrom()/sendto()

我推薦使用

recvmsg()/sendmsg()函式,

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

#include int

close

(int fd);

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

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

講完了socket有關的函式,相信你對socket有一定的了解了,下面講講臭名昭著的tcp三次握手和tcp四次放手

先上圖

客戶端先傳送乙個syn j 的報文,

伺服器接收 向客戶端傳送乙個確認的 ack j+1 ,並響應乙個syn k的報文,

客戶端接收到 向伺服器端確認乙個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返回,至此三次握手完畢,連線建立。

總結:客戶端的connect在三次握手的第二個次返回,而伺服器端的accept在三次握手的第三次返回。

四次放手圖

某個應用程序首先呼叫

close

主動關閉連線,這時tcp傳送乙個fin m;

另一端接收到fin m之後,執行被動關閉,對這個fin進行確認。它的接收也作為檔案結束符傳遞給應用程序,因為fin的接收意味著應用程序在相應的連線上再也接收不到額外資料;

一段時間之後,接收到檔案結束符的應用程序呼叫

close

關閉它的socket。這導致它的tcp也傳送乙個fin n;

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

C socket程式設計基礎 理論篇

對於socket在這裡我不想究其歷史,我只想說其時它是一種程序通訊的方式,簡言之就是呼叫這個網路庫的一些api函式就能實現分布在不同主機的相關程序之間的資料交換.socket中首先我們要理解如下幾個定義概念 二是埠號 用來標識本地通訊程序,方便os提交資料.就是說程序指定了對方程序的網路ip,但這個...

C socket程式設計基礎 理論篇

對於socket在這裡我不想究其歷史,我只想說其時它是一種程序通訊的方式,簡言之就是呼叫這個網路庫的一些api函式就能實現分布在不同主機的相關程序之間的資料交換.socket中首先我們要理解如下幾個定義概念 二是埠號 用來標識本地通訊程序,方便os提交資料.就是說程序指定了對方程序的網路ip,但這個...

C Socket通訊例子

建立兩個工程檔案,server和client include include pragma comment lib,ws2 32.lib 靜態加入乙個lib檔案 pragma warning disable 4996 using namespace std intmain 繫結ip和埠 配置監聽位址...