一、套接字(socket)概念
套接字(socket)是通信的基石,是支持TCP/IP協議的網絡通信的基本操作單元。它是網絡通信過程中端點的抽象表示,包含進行網絡通信必須的五種信息:連接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。
應用層通過傳輸層進行數據通信時,TCP會遇到同時為多個應用程序進程提供並發服務的問題。多個TCP連接或多個應用程序進程可能需要通過同一個 TCP協議端口傳輸數據。為了區別不同的應用程序進程和連接,許多計算機操作系統為應用程序與TCP/IP協議交互提供了套接字(Socket)接口。應 用層可以和傳輸層通過Socket接口,區分來自不同應用程序進程或網絡連接的通信,實現數據傳輸的並發服務。
二、建立socket連接
建立Socket連接至少需要一對套接字,其中一個運行於客戶端,稱為ClientSocket ,另一個運行於服務器端,稱為ServerSocket 。
套接字之間的連接過程分為三個步驟:服務器監聽,客戶端請求,連接確認。
- 服務器監聽:服務器端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態,等待客戶端的連接請求
- 客戶端請求:指客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址和端口號,然后就向服務器端套接字提出連接請求。
- 連接確認:當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求時,就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶 端,一旦客戶端確認了此描述,雙方就正式建立連接。而服務器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。
服務端前台XMAL
<Window x:Class="Socket通信.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Socket通信" mc:Ignorable="d" Title="服務端" Height="350" Width="525" Loaded="Window_Loaded" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50*"/>
<RowDefinition Height="190*"/>
<RowDefinition Height="81*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<WrapPanel VerticalAlignment="Center">
<Label Padding="5">IP:</Label>
<TextBox Padding="3" Width="150" Name="IP"></TextBox>
<Label Padding="5">Port:</Label>
<TextBox Padding="3" Width="100" Name="Port"></TextBox>
<Button Padding="3" Margin="3" Click="Start_View_Click">開始監聽</Button>
<Button Padding="3" Margin="3" Click="Stop_Click">停止監聽</Button>
</WrapPanel>
</Grid>
<Grid Grid.Row="1">
<ListBox Name="ListConnet"></ListBox>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="405*"/>
<ColumnDefinition Width="113*"/>
</Grid.ColumnDefinitions>
<TextBox Name="SentConnet"></TextBox>
<Button Grid.Column="1" Click="Send_Click">發送</Button>
</Grid>
</Grid>
</Window>
服務端后台代碼
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Windows; namespace Socket通信 { /// <summary>
/// MainWindow.xaml 的交互邏輯 /// </summary>
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } Socket socketSend; private void Start_View_Click(object sender, RoutedEventArgs e) { try { //點擊開始監聽時 在服務端創建一個負責監聽IP和端口號的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Any; //創建對象端口
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(Port.Text)); socketWatch.Bind(point);//綁定端口號
ShowMsg("監聽成功!"); socketWatch.Listen(10);//設置監聽 //創建監聽線程
Thread thread = new Thread(Listen); thread.IsBackground = true; thread.Start(socketWatch); } catch { } } void Listen(object o) { try { Socket socketWatch = o as Socket; while (true) { socketSend = socketWatch.Accept();//等待接收客戶端連接
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "連接成功!"); //開啟一個新線程,執行接收消息方法
Thread r_thread = new Thread(Received); r_thread.IsBackground = true; r_thread.Start(socketSend); } } catch { } } /// <summary>
/// 服務器端不停的接收客戶端發來的消息 /// </summary>
/// <param name="o"></param>
void Received(object o) { try { Socket socketSend = o as Socket; while (true) { //客戶端連接服務器成功后,服務器接收客戶端發送的消息
byte[] buffer = new byte[1024 * 1024 * 3]; //實際接收到的有效字節數
int len = socketSend.Receive(buffer); if (len == 0) { break; } string str = Encoding.UTF8.GetString(buffer, 0, len); ShowMsg("接收到的客戶端數據:" + socketSend.RemoteEndPoint + ":" + str); } } catch { } } /// <summary>
/// 服務器向客戶端發送消息 /// </summary>
/// <param name="str"></param>
void Send(string str) { byte[] buffer = Encoding.UTF8.GetBytes(str); socketSend.Send(buffer); } void ShowMsg(string msg) { Dispatcher.Invoke(() => { ListConnet.Items.Add(msg + "\r\n"); }); } private void Send_Click(object sender, RoutedEventArgs e) { Send(SentConnet.Text.Trim()); } private void Window_Loaded(object sender, RoutedEventArgs e) { } private void Stop_Click(object sender, RoutedEventArgs e) { socketSend.Close(); ShowMsg("已經停止監聽!"); } } }
客戶端前台XMAL
<Window x:Class="Socket_Client.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Socket_Client" mc:Ignorable="d" Title="客戶端" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50*"/>
<RowDefinition Height="190*"/>
<RowDefinition Height="81*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<WrapPanel VerticalAlignment="Center">
<Label Padding="5">IP:</Label>
<TextBox Padding="3" Width="150" Name="IP"></TextBox>
<Label Padding="5">Port:</Label>
<TextBox Padding="3" Width="100" Name="Port"></TextBox>
<Button Padding="3" Margin="3" Click="Start_View_Click">連接</Button>
<Button Padding="3" Margin="3" Click="Stop_Click">斷開連接</Button>
</WrapPanel>
</Grid>
<Grid Grid.Row="1">
<TextBox Name="ListConnet"></TextBox>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="405*"/>
<ColumnDefinition Width="113*"/>
</Grid.ColumnDefinitions>
<TextBox Name="SentConnet"></TextBox>
<Button Grid.Column="1" Click="Send_Click">發送</Button>
</Grid>
</Grid>
</Window>
客戶端后台代碼
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Socket_Client { /// <summary>
/// MainWindow.xaml 的交互邏輯 /// </summary>
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } Socket socketSend; private void Start_View_Click(object sender, RoutedEventArgs e) { try { //創建客戶端Socket,獲得遠程ip和端口號
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(IP.Text); IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(Port.Text)); socketSend.Connect(point); ShowMsg("連接成功!"); //開啟新的線程,不停的接收服務器發來的消息
Thread c_thread = new Thread(Received); c_thread.IsBackground = true; c_thread.Start(); } catch (Exception) { ShowMsg("IP或者端口號錯誤..."); } } void ShowMsg(string str) { Dispatcher.Invoke(() => { ListConnet.AppendText(str + "\r\n"); }); } /// <summary>
/// 接收服務端返回的消息 /// </summary>
void Received() { while (true) { try { byte[] buffer = new byte[1024 * 1024 * 3]; //實際接收到的有效字節數
int len = socketSend.Receive(buffer); if (len == 0) { continue; } string str = Encoding.UTF8.GetString(buffer, 0, len); ShowMsg("接收到的服務端數據:" + socketSend.RemoteEndPoint + ":" + str); } catch { } } } private void Send_Click(object sender, RoutedEventArgs e) { try { string msg = SentConnet.Text.Trim(); byte[] buffer = new byte[1024 * 1024 * 3]; buffer = Encoding.UTF8.GetBytes(msg); socketSend.Send(buffer); } catch { } } private void Stop_Click(object sender, RoutedEventArgs e) { socketSend.Close(); ShowMsg("連接已經斷開!"); } } }
轉:https://www.cnblogs.com/TechnologyDictionary/archive/2019/02/22/10423068.html