Socket 網路編程,socket網路編程
<.>
用戶端要串連伺服器:首先要知道伺服器的IP地址。而伺服器裡有很多的應用程式,每一個應用程式對應一個連接埠號碼
所以用戶端想要與伺服器中的某個應用程式進行通訊就必須要知道那個應用程式的所在伺服器的IP地址,及應用程式所對應的連接埠號碼
TCP協議:安全穩定,一般不會發生資料丟失,但是效率低。利用TCP發生資料一般經過3次握手(所有效率低,自己百度三向交握)
UDP協議:快速,效率高,但是不穩定,容易發生資料丟失(沒有經過三向交握,不管伺服器有空沒空,資訊全往伺服器發,所有效率搞,但伺服器忙的時候就沒辦法處理你的資料,容易造成資料丟失,不穩定)
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Net.Sockets;using System.Net;using System.Threading;namespace Socket通訊{ public partial class Form1 : Form { public Form1() { InitializeComponent(); this.txtPort.Text = "5000"; this.txtIp.Text = "192.168.137.1"; } private void btnStart_Click(object sender, EventArgs e) { //當點擊開始監聽的時候,在伺服器端建立一個負責監聽IP地址跟連接埠號碼的Socket Socket socketWatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); //Any:提供一個 IP 位址,指示伺服器應偵聽所有網路介面上的用戶端活動。此欄位為唯讀。 IPAddress ip = IPAddress.Any; //建立連接埠號碼對象;將txtPort.Text控制項的值設為服務端的連接埠號碼 IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text)); //監聽 socketWatch.Bind(point); ShowMsg("監聽成功"); socketWatch.Listen(10);//串連隊列的最大長度 ;即:一個時間點內最大能讓幾個用戶端串連進來,超過長度就進行排隊 //等待用戶端串連;Accept()這個方法能接收用戶端的串連,並為新串連建立一個負責通訊的Socket Thread th = new Thread(Listen); //被線程執行的方法如果有參數的話,參數必須是object類型 Control.CheckForIllegalCrossThreadCalls = false; //因為.net不允許跨線程訪問的,所以這裡取消跨線程的檢查。.net不檢查是否有跨線程訪問了,所有就不會報: “從不是建立控制項“txtLog”的線程訪問它” 這個錯誤了,從而實現了跨線程訪問 th.IsBackground = true; //將th這個線程設為後台線程。 //Start(object parameter); parameter:一個對象,包含線程執行的方法要使用的資料,即線程執行Listen方法,Listen的參數 th.Start(socketWatch); //這個括弧裡的參數其實是Listen()方法的參數。因為Thread th = new Thread(Listen)這個括弧裡只能寫方法名(函數名) 但是Listen()方法是有參數的,所有就要用Start()方法將它的參數添加進來 } /// <summary> /// 等待用戶端串連,如果監控到有用戶端串連進來就建立一個與之通訊的Socket /// </summary> /// <param name="o"></param> void Listen(object o) //這裡為什麼不直接傳遞Socket類型的參數呢? 原因是:被線程執行的方法如果有參數的話,參數必須是object類型 { Socket socketWatch = o as Socket; while (true) //為什麼這裡要有個while迴圈?因為當一個人串連進來的時候建立了與之通訊的Socket後就程式就會往下執行了,就不會再回來為第二個人的串連建立負責通訊的Socket了。(應該是每個人(每個用戶端)建立一個與之通訊的Socket)所以要寫在迴圈裡。 { //等待用戶端串連;Accept()這個方法能接收用戶端的串連,並為新串連建立一個負責通訊的Socket Socket socketSend = socketWatch.Accept(); dic.Add(socketSend.RemoteEndPoint.ToString(), socketSend); //(根據用戶端的IP地址和連接埠號碼找負責通訊的Socket,每個用戶端對應一個負責通訊的Socket),ip地址及連接埠號碼作為鍵,將負責通訊的Socket作為值填充到dic索引值對中。 //我們通過負責通訊的這個socketSend對象的一個RemoteEndPoint屬性,能夠拿到遠程連過來的用戶端的Ip地址跟連接埠號碼 ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "串連成功");//效果:192.168.1.32:串連成功 comboBox1.Items.Add(socketSend.RemoteEndPoint.ToString()); //將串連過來的每個用戶端都添加到combBox控制項中。 //用戶端串連成功後,伺服器應該接收用戶端發來的訊息。 Thread getdata = new Thread(GetData); getdata.IsBackground = true; getdata.Start(socketSend); } } Dictionary<string, Socket> dic = new Dictionary<string, Socket>(); /// <summary> /// 不停的接收用戶端發送過來的訊息 /// </summary> /// <param name="o"></param> void GetData(object o) { while (true) { Socket socketSend = o as Socket; //將用戶端發過來的資料先放到一個位元組數組裡面去 byte[] buffer = new byte[1024 * 1024 * 2]; //建立一個位元組數組,位元組數組的長度為2M //實際接收到的有效位元組數; (利用Receive方法接收用戶端傳過來的資料,然後把資料儲存到buffer位元組數組中,返回一個接收到的資料的長度) int r = socketSend.Receive(buffer); if (r == 0) //如果接收到的有效位元組數為0 說明用戶端已經關閉了。這時候就跳出迴圈了。 { //只有用戶端給使用者發訊息,不可能是發0個長度的位元組。即便發空訊息,空訊息也是有過個長度的。所有接收到的有效位元組長度為0就代表用戶端已經關閉了 break; } //將buffer這個位元組數組裡面的資料按照UTF8的編碼,解碼成我們能夠讀懂的的string類型,因為buffer這個數組的實際儲存資料的長度是r個 ,所以從索引為0的位元組開始解碼,總共解碼r個位元組長度。 string str = Encoding.UTF8.GetString(buffer, 0, r); ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str); } } private void ShowMsg(string str) { txtLog.AppendText(str + "\r\n"); //將str這個字串添加到txtLog這個文字框中。 } /// <summary> /// 服務端給用戶端發資訊 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSend_Click_1(object sender, EventArgs e) { if (comboBox1.SelectedItem == null) //如果comboBox控制項沒有選中值。就提示使用者選擇用戶端 { MessageBox.Show("請選擇用戶端"); return; } string str = txtMes.Text; //擷取使用者輸入的內容 (服務端要給用戶端發的資訊) byte[] strByte = Encoding.Default.GetBytes(str); //將資訊轉換成二進位位元組數組 string getIp = comboBox1.SelectedItem as string; //comboBox儲存的是用戶端的(ip+連接埠號碼) Socket socketSend = dic[getIp] as Socket; //根據這個(ip及連接埠號碼)去dic索引值對中找對應 賦值與用戶端通訊的Socket【每個用戶端都有一個負責與之通訊的Socket】 socketSend.Send(strByte); //將資訊發送到用戶端 } }}
開開啟始命令 cmd telnet 10.18.16.46 5000 即telnet 伺服器ip地址 綁定的連接埠號碼