總結:
服務器端先創建一個socketwatch監控等待客戶端連接,客戶端連接后循環socketwatch.accept()創建多個通信線程,每個通信線程再創建新的數據處理線程,數據必須循環接收
客戶端沒有socketwatch,直接創建socket,連接用connect(),發送用socket.send(),接收用receive(),數據也是循環接收的
一、服務器端單線程流程:
//服務器創建一個socket用於監聽 Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //設置ip和端口 IPAddress ip = IPAddress.Any; IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text)); //綁定,即監聽 socketwatch.Bind(endpoint); //設置監聽數量 socketwatch.Listen(10); Msger("監聽成功!"+"\n\r"); //等待客戶端連接,並創建一個負責通信的socket, 單線程的話會一直等待accept(),卡死 Socket socketsend = socketwatch.Accept(); //接收遠程連接的ip信息 Msger(socketsend.RemoteEndPoint.ToString()+" 連接進來");
服務器端多線程: 一個監聽socket可以創建多個通信socket,監聽socket循環創建多個通信socket線程,其中每個通信socket再創建一個線程處理信息,預防卡死
private void button1_Click(object sender, EventArgs e) { //服務器創建一個socket用於監聽 Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //設置ip和端口 IPAddress ip = IPAddress.Any; IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text)); //綁定,即監聽 socketwatch.Bind(endpoint); //設置監聽數量 socketwatch.Listen(10); Msger("監聽成功!" + "\n\r"); //創建線程預防卡死 Thread th = new Thread(Listen); th.IsBackground = true; th.Start(socketwatch);// 傳入監聽進程 } //監聽socket循環創建多個通信socket線程,其中每個通信socket再創建一個線程處理信息,預防卡死 private void Listen(object s) { //類型轉換,as轉換成功返回值否則NULL Socket socketwatch = s as Socket; //等待客戶端連接,並創建一個負責通信的socket while (true) { Socket socketsend = socketwatch.Accept(); Msger(socketsend.RemoteEndPoint.ToString() + " 連接進來" + "\t\r\n"); //創建一個新的線程處理客戶端發送過來的信息,否則一個socket就堵塞 Thread th = new Thread(Operater); th.IsBackground = true; th.Start(socketsend); } } /// <summary> /// 信息處理線程 /// </summary> /// <param name="s">socket返回客戶端信息</param> public void Operater(object s) { Socket socketsend = s as Socket; //必須循環接收消息 while (true) { //創建字節數組並接受傳過來的數據,返回int為實際使用值 byte[] receive = new byte[1024 * 1024 * 2]; int realr = socketsend.Receive(receive); //判斷客戶端發送的內容,如果為0則停止循環 if (realr == 0) { break; } //解碼 string text = Encoding.UTF8.GetString(receive, 0, realr); //寫入textbox Msger(text); } } public void Msger(string ms) { textBox3.AppendText(ms + "\n\r"); //追加方式 }
二、客戶端簡單流程:
private void button4_Click(object sender, EventArgs e) { //創建socket socketcustomsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //設置ip和port IPAddress ip = IPAddress.Parse(textBox5.Text); IPEndPoint ipendpoint = new IPEndPoint(ip, Convert.ToInt32(textBox6.Text)); //連接 socketcustomsend.Connect(ipendpoint); textBox4.Text = "連接成功!"; //創建進程接受服務器傳來的信息 Thread th = new Thread(CustomReceive); th.IsBackground = true; th.Start(socketcustomsend); } /// <summary> /// 循環接受服務器傳來的信息 /// </summary> /// <param name="s">通信的socket</param> public void CustomReceive(object s) { while (true) //循環接收信息 { Socket socketcustomsend = s as Socket; byte[] b = new byte[1024 * 1024 * 5]; int r = socketcustomsend.Receive(b); if (r==0) //0表示服務器端關閉 { break; } textBox4.Text = Encoding.UTF8.GetString(b, 0, r); } }
三、通信的例子
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace socket通信 { public partial class socket練習 : Form { public socket練習() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; } private void label1_Click(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { //服務器創建一個socket用於監聽 Socket socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //設置ip和端口 IPAddress ip = IPAddress.Any; IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text)); //綁定,即監聽 socketwatch.Bind(endpoint); //設置監聽數量 socketwatch.Listen(10); Msger("監聽成功!" + "\n\r"); //創建線程預防卡死 Thread th = new Thread(Listen); th.IsBackground = true; th.Start(socketwatch);// 傳入監聽進程 } //監聽socket循環創建多個通信socket線程,其中每個通信socket再創建一個線程處理信息,預防卡死 // 全局服務器端通信socket Socket socketsend; Dictionary<string, Socket> sdic = new Dictionary<string, Socket>(); private void Listen(object s) { //類型轉換,as轉換成功返回值否則NULL Socket socketwatch = s as Socket; //等待客戶端連接,並創建一個負責通信的socket while (true) { socketsend = socketwatch.Accept(); //將socket與ip信息放入字典集合 sdic.Add(socketsend.RemoteEndPoint.ToString(), socketsend); //加入combox列表 comboBox1.Items.Add(socketsend.RemoteEndPoint.ToString()); //讓combox顯示當前連接的socket comboBox1.SelectedItem= socketsend.RemoteEndPoint.ToString(); Msger(socketsend.RemoteEndPoint.ToString() + " 連接進來了" + "\t\r\n"); //創建一個新的線程處理客戶端發送過來的信息,否則一個socket就堵塞 Thread th = new Thread(Operater); th.IsBackground = true; th.Start(socketsend); } } /// <summary> /// 信息處理線程 /// </summary> /// <param name="s">socket返回客戶端信息</param> public void Operater(object s) { Socket socketsend = s as Socket; //必須循環接收消息 while (true) { //創建字節數組並接受傳過來的數據,返回int為實際使用值 byte[] receive = new byte[1024 * 1024 * 10]; int realr = socketsend.Receive(receive); //判斷客戶端發送的內容,如果為0則停止循環 if (realr == 0) { break; } //用文件頭判斷傳過來的是文字信息或文件的各種類型,0-文字信息 1-文件 if (receive[0]==0) { //解碼 string text = Encoding.UTF8.GetString(receive, 1, realr-1); //寫入textbox Msger(text); } else if(receive[0]==1) //文件則保存 { SaveFileDialog sf = new SaveFileDialog(); sf.Filter = "所有文件|*.*"; sf.ShowDialog(this); //注意this用法 using (FileStream fs=new FileStream(sf.FileName,FileMode.Create,FileAccess.Write)) { fs.Write(receive, 1, realr-1); //-1去掉標志頭 } } } } public void Msger(string ms) { textBox3.AppendText(ms + "\n"); //追加方式 } private void textBox1_TextChanged(object sender, EventArgs e) { } private void textBox2_TextChanged(object sender, EventArgs e) { } private void label5_Click(object sender, EventArgs e) { } private void label6_Click(object sender, EventArgs e) { } //客戶端socket Socket socketcustomsend; private void button4_Click(object sender, EventArgs e) { //創建socket socketcustomsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //設置ip和port IPAddress ip = IPAddress.Parse(textBox5.Text); IPEndPoint ipendpoint = new IPEndPoint(ip, Convert.ToInt32(textBox6.Text)); //連接 socketcustomsend.Connect(ipendpoint); textBox4.Text = "連接成功!"; //創建進程接受服務器傳來的信息 Thread th = new Thread(CustomReceive); th.IsBackground = true; th.Start(socketcustomsend); } /// <summary> /// 循環接受服務器傳來的信息 /// </summary> /// <param name="s">通信的socket</param> public void CustomReceive(object s) { while (true) //循環接收信息 { Socket socketcustomsend = s as Socket; byte[] b = new byte[1024 * 1024 * 5]; int r = socketcustomsend.Receive(b); if (r==0) //0表示服務器端關閉 { break; } textBox4.Text = Encoding.UTF8.GetString(b, 0, r); } } private void button2_Click(object sender, EventArgs e) { //准備數據 byte[] b = Encoding.UTF8.GetBytes(textBox4.Text); //加入識別頭0 List<byte> nb = new List<byte>(); nb.Add(0); nb.AddRange(b); byte[] sb= nb.ToArray(); //發送 socketcustomsend.Send(sb); } private void button6_Click(object sender, EventArgs e) { textBox3.Clear(); } private void button5_Click(object sender, EventArgs e) { OpenFileDialog of = new OpenFileDialog(); of.Multiselect = false; of.Filter = "所有文件|*.*"; of.ShowDialog(); textBox7.Text = of.FileName; } private void button3_Click(object sender, EventArgs e) { using (FileStream fs = new FileStream(textBox7.Text, FileMode.Open, FileAccess.Read)) { byte[] b = new byte[1024 * 1024 * 10]; //返回真實使用數 int r = fs.Read(b, 0, b.Length); //添加文件類型識別頭,list與array互相轉換 List<byte> newbyte = new List<byte>(); newbyte.Add(1);//1代表文件 newbyte.AddRange(b);//將b中元素添加,add()為整個添加 byte[] nb=newbyte.ToArray(); //發送真實大小數據, 為r+1 socketcustomsend.Send(nb,0,r+1,SocketFlags.None); } } private void button7_Click(object sender, EventArgs e) { sdic[comboBox1.SelectedItem.ToString()].Send(Encoding.UTF8.GetBytes(textBox3.Text)); } } }