當初寫第一個網絡程序的時候,就是通過搜索,找各種實例把程序拼湊出來的,并沒有進行深入的理解。這個東西用了這么多年,是該來沉淀一下了,也檢驗一下自己對這塊知識的掌握程度。
可以說,一個典型的網絡程序是離不開socket的,它是系統提供給開發者們進行網絡操作的強大武器。
socket又叫套接字,是一系列網絡操作的API。它的實現和表現形式又會根據系統平臺的不同、編程語言的不同而有所區別,但是實現的功能都是一致的。
socket的創建:
windows平臺C版本
SOCKET s = socket(AF_.NET, SOCK_STREAM, IPPROTO_TCP);
C#版本
Socket s=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
上面兩個套接字都是以TCP協議創建的,socket中的三個參數分別指定了IP層協議類型(IPV4和IPV6),數據交互格式(字節流,數據報等),傳輸層協議(TCP和UDP)。
套接字在進程中是以文件描述符的形式存在的,其實就是一個數字,用來唯一標識一個套接字,以不同的形式提供給開發者使用。
socket的地址和端口:
地址指定了數據交互節點的設備,如果一臺設備有多塊網卡,則地址指定的就是某一塊網卡;端口標識的是設備上的某個進程。來自網絡的數據到達網卡后,向上經過數據鏈路層,網絡層,到達傳輸層,然后根據端口確定需要將數據交給哪個進程。
數據接收:
數據接收是由進程調用socket的接收函數發起的。該函數會向系統提交接收數據的IO請求,該請求的內容包括應用層存放數據的緩沖區,請求的數據尺寸,在緩沖區中存放數據的偏移值。
C# 發起數據接收請求:
int rcvLen=m_socket.Receive(buf, offset, size, SocketFlags.None);
其中buf為數據緩沖區,offset為數據接收時在buf中存放數據的起始地址,size為此次請求的字節大小,rcvLen為此次接收成功后實際接收到的字節長度。
數據發送:
數據的發送是進程調用socket的發送函數發起的。該函數會向系統提交發送數據的IO請求,向指定的節點發送數據,請求的內容包括發送的數據內容,長度等。
C# 發起的數據發送請求(TCP):
int sndLen= m_socket.Send(buf);
其中buf為發送的內容字節碼數組,sndLen為實際發送的字節長度。
TCP Socket:
TCP是傳輸層的協議,該協議有一定的復雜性,目的是完成數據的可靠傳輸。采用TCP實現的網絡應用,分為服務端和客戶端兩種端點類型,每個端的實現都對應著不同socket調用函數。
服務端可以接受客戶端的連接請求,連接完成后就可以進行雙向通信。
建立服務端,需要創建服務端套接字,為該套接字綁定服務地址和端口,打開被動監聽,開始等待連接。
C#版本的服務端建立代碼
m_socketServer = CreateSocket_IPV4();
m_socketServer.Bind(CreateEndPoint(port, null));
m_socketServer.Listen(10);
m_conns = new List<IConnection>();
Task.Factory.StartNew(() =>
{
while (m_running)
{
var s = m_socketServer.Accept();
var conn = CreateConnection(s);
m_conns.Add(conn);
OnConnected?.Invoke(conn);
}
});
客戶端的操作相對簡單一些,只需要創建套接字然后向服務端發起連接請求。
C#版本的客戶端代碼
var s = CreateSocket_IPV4();
s.Connect(IPAddress.Parse(ip), port);
socket涵蓋的內容是非常豐富的,我們在此只是拿出一些代表性的內容來記述。