1、Socket相關概念[端口]
2、Socket一般應用模式(服務器端和客戶端)
3、Socket的通訊過程
4、Socket的構造函數
5、Socket通信基本流程圖
6、基於TCP的Socket編程
7、Socket源代碼
1、Socket相關概念[端口]
在Internet上有很多這樣的主機,這些主機一般運行了多個服務軟件,同時提供幾種服務。
每種服務都打開一個Socket,並綁定到一個端口上,不同的端口對應於不同的服務(應用程序)。
例如:http 使用80端口 ftp使用21端口 smtp 25端口
有兩種類型:50000
流式Socket(STREAM):
是一種面向連接的Socket,針對於面向連接的TCP服務應用,安全,但是效率低;
數據報式Socket(DATAGRAM):
是一種無連接的Socket,對應於無連接的UDP服務應用.不安全(丟失,順序混亂,在接收端要分析重排及要求重發),但效率高.
端口用來標識計算機里的某個程序。
按端口號可分為3大類
(1) 公認端口(WellKnownPorts):從0到1023,它們緊密綁定(binding)於一些服務。
通常這些端口的通訊明確表明了某種服務的協議。例如:80端口實際上總是HTTP通訊。
(2) 注冊端口(RegisteredPorts):從1024到49151。它們松散地綁定於一些服務。
也就是說有許多服務綁定於這些端口,這些端口同樣用於許多其它目的。例如:許多系統處理動態端口從1024左右開始。
(3) 動態和/或私有端口(Dynamicand/orPrivatePorts):從49152到65535。
理論上,不應為服務分配這些端口。實際上,機器通常從1024起分配動態端口。
2、Socket一般應用模式(服務器端和客戶端)
1.服務端welcoming socket 開始監聽端口(負責監聽客戶端連接信息)
2.客戶端client socket連接服務端指定端口(負責接收和發送服務端消息)
3.服務端welcoming socket 監聽到客戶端連接,創建connection socket。(負責和客戶端通信)
服務器端的Socket(至少需要兩個)
一個負責接收客戶端連接請求(但不負責與客戶端通信)
每成功接收到一個客戶端的連接便在服務端產生一個對應的負責通信的Socket
在接收到客戶端連接時創建.
為每個連接成功的客戶端請求在服務端都創建一個對應的Socket(負責和客戶端通信).
客戶端的Socket
必須指定要連接的服務端地址和端口。
通過創建一個Socket對象來初始化一個到服務器端的TCP連接。
3、Socket的通訊過程
服務器端:
申請一個socket
綁定到一個IP地址和一個端口上
開啟偵聽,等待接授連接
客戶端:
申請一個socket
連接服務器(指明IP地址和端口號)
服務器端接到連接請求后,產生一個新的socket(端口大於1024)與客戶端建立連接並進行通訊,原監聽socket繼續監聽。
4、Socket的構造函數
連接通過構造函數完成。
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
AddressFamily 成員指定 Socket 用來解析地址的尋址方案。例如,InterNetwork 指示當 Socket 使用一個 IP 版本 4 地址連接。
SocketType 定義要打開的 Socket 的類型
Socket 類使用 ProtocolType 枚舉向 Windows Sockets API 通知所請求的協議
如:mySocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
AddressFamily.InterNetWork:使用 IP4地址。
SocketType.Stream:支持可靠、雙向、基於連接的字節流,而不重復數據。
此類型的 Socket 與單個對方主機進行通信,並且在通信開始之前需要遠程主機連接。
Stream 使用傳輸控制協議 (Tcp) ProtocolType 和 InterNetworkAddressFamily。
ProtocolType.Tcp:使用傳輸控制協議。
注意點:
l 至少要定義一個要連接的遠程主機的IP和端口號。
l 端口號必須在 1 和 65535之間,最好在1024以后。
l 要連接的遠程主機必須正在監聽指定端口,也就是說你無法隨意連接遠程主機。
如:
IPAddress addr = IPAddress.Parse("127.0.0.1");
IPEndPoint endp = new IPEndPoint(addr, 10001);
服務端先綁定:serverWelcomeSocket.Bind(endp)
客戶端再連接:clientSocket.Connect(endp)
l 一個Socket一次只能連接一台主機。
l Socket關閉后無法再次使用。
l 每個Socket對象只能一台遠程主機連接. 如果你想連接到多台遠程主機, 你必須創建多個Socket對象。
Socket方法:
------------------相關類--------------------------
IPAddress類:包含了一個IP地址
IPEndPoint類:包含了一對IP地址和端口號
--------------------方法們------------------------------
Socket (): 創建一個Socket
Bind(): 綁定一個本地的IP和端口號(IPEndPoint)
Listen(): 讓Socket偵聽傳入的連接嘗試,並指定偵聽隊列容量
Connect(): 初始化與另一個Socket的連接
Accept(): 接收連接並返回一個新的socket
Send(): 輸出數據到Socket
Receive(): 從Socket中讀取數據
Close(): 關閉Socket (銷毀連接)
5、Socket通信基本流程圖
6、基於TCP的Socket編程
TCP service:可靠的字節流傳輸
7、Socket源代碼:
引用的鏈接:http://pan.baidu.com/s/1i3EX7lN 密碼:d148
本文的鏈接可以直接下載:源碼下載
源碼 -- 圖示如下
部分代碼展示
SocketClient

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; namespace _20151110_SocketClient { public partial class SocketClient : Form { Socket socketSend; public SocketClient() { InitializeComponent(); } #region SocketClient_Load private void SocketClient_Load(object sender, EventArgs e) { //取消跨線程檢查操作 Control.CheckForIllegalCrossThreadCalls = false; } #endregion #region btnStartConnect_Click private void btnStartConnect_Click(object sender, EventArgs e) { try { socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint point = new IPEndPoint(IPAddress.Parse(txtIP.Text.Trim()), Convert.ToInt32(txtPort.Text.Trim())); socketSend.Connect(point); ShowMsgSend(string.Format("連接{0}服務器成功!",txtIP.Text.Trim())); Thread th = new Thread(Receive); th.IsBackground = true; th.Start(); //禁用Connect button btnStartConnect.Enabled = false; } catch (Exception) { MessageBox.Show("服務器暫時沒有開啟,請稍后再試!"); } } #endregion #region btnSendMsg_Click private void btnSendMsg_Click(object sender, EventArgs e) { try { string strMsg = txtMsg.Text.Trim(); byte[] buffer = Encoding.UTF8.GetBytes(strMsg); socketSend.Send(buffer); ShowMsgLocal(string.Format("{0}--{1}:\r\n{2}", "LocalHost", DateTime.Now.ToString(), strMsg)); //清除文本框中的內容 txtMsg.Clear(); } catch (Exception) { } } #endregion #region Receive private void Receive() { try { while (true) { byte[] buffer = new byte[1024 * 1024 * 5]; int r = socketSend.Receive(buffer); if (r == 0) { break; } string strMsg = Encoding.UTF8.GetString(buffer, 0, r); ShowMsgSend(string.Format("{0}--{1}:\r\n{2}", socketSend.RemoteEndPoint.ToString(), DateTime.Now.ToString(), strMsg)); } } catch (Exception) { } } #endregion #region ShowMsgSend private void ShowMsgSend(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion #region ShowMsgLocal private void ShowMsgLocal(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion #region SocketClient_FormClosing private void SocketClient_FormClosing(object sender, FormClosingEventArgs e) { try { socketSend.Close(); } catch (Exception) { } } #endregion } }
SocketServer

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows.Forms; namespace _20151110_SocketServer { public partial class SocketServer : Form { Socket socketWatch; Socket socketSend; Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>(); public SocketServer() { InitializeComponent(); } #region SocketServer_Load private void SocketServer_Load(object sender, EventArgs e) { //取消跨線程檢查 Control.CheckForIllegalCrossThreadCalls = false; } #endregion #region btnStartBind_Click private void btnStartBind_Click(object sender, EventArgs e) { try { socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint point = new IPEndPoint(IPAddress.Parse(txtIP.Text.Trim()), Convert.ToInt32(txtPort.Text.Trim())); socketWatch.Bind(point); ShowMsgSend("監聽成功!!!"); socketWatch.Listen(10); //Thread Thread th = new Thread(Accept); th.IsBackground = true; th.Start(socketWatch); //禁用StartBind button btnStartBind.Enabled = false; } catch (Exception ex) { MessageBox.Show(ex.Message); } } #endregion #region btnSendMsg_Click private void btnSendMsg_Click(object sender, EventArgs e) { try { string strMsg = txtMsg.Text.Trim(); byte[] buffer = Encoding.UTF8.GetBytes(strMsg); string selectedIP = cboUserList.SelectedItem.ToString(); dicSocket[selectedIP].Send(buffer); ShowMsgLocal(string.Format("{0}--{1}:\r\n{2}", "LocalHost", DateTime.Now.ToString(), strMsg)); //清除文本框中的內容 txtMsg.Clear(); } catch (Exception) { } } #endregion #region Accept private void Accept(object socketObj) { try { Socket socketWatch = socketObj as Socket; while (true) { socketSend = socketWatch.Accept(); ShowMsgSend(socketSend.RemoteEndPoint.ToString() + "連接成功"); dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend); cboUserList.Items.Add(socketSend.RemoteEndPoint.ToString()); //設置Combobox的默認值 if (cboUserList.Items.Count > 0) { cboUserList.SelectedIndex = 0; } Thread th = new Thread(Receive); th.IsBackground = true; th.Start(); } } catch (Exception) { } } #endregion #region Receive private void Receive() { try { while (true) { byte[] buffer = new byte[1024 * 1024 * 5]; int r = socketSend.Receive(buffer); if (r == 0) { break; } string strMsg = Encoding.UTF8.GetString(buffer, 0, r); ShowMsgSend(string.Format("{0}--{1}:\r\n{2}", socketSend.RemoteEndPoint.ToString(), DateTime.Now.ToString(), strMsg)); } } catch (Exception) { } } #endregion #region ShowMsgSend private void ShowMsgSend(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion #region ShowMsgLocal private void ShowMsgLocal(string strMsg) { txtLog.AppendText(strMsg + "\r\n"); } #endregion private void SocketServer_FormClosing(object sender, FormClosingEventArgs e) { try { socketSend.Close(); } catch (Exception) { } } } }
本文引自:https://www.cnblogs.com/wt627939556/p/6675247.html