Socket-服务器端与客户端互相通信
一.连接
1.服务器端开始监听
2.客户端Connect()连接服务器端
3.服务器端Accept()产生新的socket,一次连接完成,此时服务器端与客户端就可以使用Send和Receive发送和接受数据
二.发送数据和文件
1.一端发送数据时,在包头(也可以包尾)加上特殊一个字符(比如0和1),另一端先判断包的第一个字符是什么,比如0就是字符串,1就是文件,然后读取数据
2.一段发送文件时,应该先发送文件名,再发送文件,另一端先获取文件名,再根据文件名,把数据保存本地。
三.代码
客户端代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; namespace SOCKET_Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.FormClosed += Form1_FormClosed; } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { SafeClose(socketSend); } Socket socketSend; string FileName; private void button1_Click(object sender, EventArgs e) { try { // 创建负责通信的Socket socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(TxtIpAddress.Text.Trim()); IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text.Trim())); // 获得要连接的远程服务器应用程序的ip地址和端口号 socketSend.Connect(point); ShowMsg("连接成功"); // 开启一个新的线程不停的接受服务端发来的消息 Thread th = new Thread(Recive); th.IsBackground = true; th.Start(); } catch { } } /// <summary> /// 不停的接受服务器发来的消息 /// </summary> void Recive() { try { while (true) { byte[] buffer = new byte[1024 * 1024 * 3]; // 实际接受到的有效字节数 int r = socketSend.Receive(buffer); if (r == 0) { break; } // 判断第一位 switch (buffer[0]) { case 0: string str = Encoding.UTF8.GetString(buffer, 1, r-1); //MessageBox.Show(str); ShowMsg(socketSend.RemoteEndPoint + ":" + str); break; case 1: using(FileStream fsWrite=new FileStream(@"C:\"+FileName,FileMode.OpenOrCreate,FileAccess.Write)) { fsWrite.Write(buffer,1,r-1); } MessageBox.Show("保存成功!"); break; case 3: //获取文件文件名 FileName = Encoding.UTF8.GetString(buffer, 1, r - 1); break; case 2: ZhenDong(); break; } } } catch { } } /// <summary> /// 震动 /// </summary> void ZhenDong() { int posX = this.Location.X; int posY = this.Location.Y; for (int i = 0; i < 300; i++) { this.Location = new Point(posX-200,posY-200); this.Location = new Point(posX, posY); } } void ShowMsg(string str) { richTextBox1.AppendText(str + "\r\n"); } /// <summary> /// 客户端给服务器发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { try { if (richTextBox2.Text.Trim() == "") { MessageBox.Show("当前无发送内容!"); return; } string str = richTextBox2.Text.Trim(); byte[] buffer = Encoding.UTF8.GetBytes(str); socketSend.Send(buffer); richTextBox2.Clear(); } catch { } } public void SafeClose( Socket socket) { if (socket == null) return; if (!socket.Connected) return; try { socket.Shutdown(SocketShutdown.Both); } catch { } try { socket.Close(); } catch { } } private void Form1_Load(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; } private void button3_Click(object sender, EventArgs e) { SafeClose(socketSend); } } }
服务器端代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; using System.IO; using Timer = System.Windows.Forms.Timer; namespace SOCKET_Test { public partial class Form1 : Form { public Form1() { InitializeComponent(); } Thread th; Thread thAccept; private void btnStart_Click(object sender, EventArgs e) { try { // 当点击开始监听的时候,在服务器端创建一个负责监听Ip地址跟端口号的Socket Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Any; // IPAddress.Parse(txtserver.text) // 创建端口号对象 IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text.Trim())); // 监听 socketWatch.Bind(point); ShowMsg("监听成功"); socketWatch.Listen(10); Timer timer = new Timer(); timer.Tick += Timer_Tick; timer.Interval = 1000; //timer.tick+= new ElapsedEventHandler(timer_Elapsed); timer.Start(); th = new Thread(Listen); th.IsBackground = true; th.Start(socketWatch); } catch (Exception o) { MessageBox.Show(o.ToString()); } } private void Timer_Tick(object sender, EventArgs e) { if (dicSocket.Count > 0) { for (int i = dicSocket.Count - 1; i >= 0; i--) { string sendStr = "Server Information"; byte[] bs = Encoding.ASCII.GetBytes(sendStr); if (dicSocket.ToList()[i].Value.Poll(1000, SelectMode.SelectRead)) //SelectMode.SelectRead表示,如果已调用 并且有挂起的连接,true。 //- 或 - 如果有数据可供读取,则为 true。- 或 - 如果连接已关闭、重置或终止,则返回 true(此种情况就表示若客户端断开连接了,则此方法就返回true); 否则,返回 false。 { //dicSocket.ToList()[i].Value.Close();//关闭socket dicSocket.ToList().RemoveAt(i);//从列表中删除断开的socke comboBox1.Items.Remove(dicSocket.ToList()[i].Value.RemoteEndPoint.ToString()); continue; } dicSocket.ToList()[i].Value.Send(bs, bs.Length, 0); } } } Socket socketSend; /// <summary> /// 等待客户端的链接,并且创建与之通信用的Socket /// </summary> void Listen(object obj) { Socket socketWatch = obj as Socket; // 等待客户端的连接 while(true) { try { socketSend = socketWatch.Accept(); // 将远程连接的客户端的IP地址和Socket存入集合中 dicSocket.Add(socketSend.RemoteEndPoint.ToString(),socketSend); comboBox1.Items.Add(socketSend.RemoteEndPoint.ToString()); ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功"); // 客户端连接成功之后,服务器应该接受客户端发来的消息 thAccept = new Thread(Recive); thAccept.IsBackground = true; thAccept.Start(socketSend); } catch { } } } // 将远程连接的客户端的IP地址和Socket存入集合中 Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>(); /// <summary> /// 服务器不停的接受客户端发送过来的请求 /// </summary> /// <param name="obj"></param> public void Recive(object obj) { Socket socketSend = obj as Socket; while(true) { try { byte[] buffer = new byte[1024 * 1024 * 2]; // 实际接受到的有效字节数 int r = socketSend.Receive(buffer); if (r == 0) { break; } string str = Encoding.UTF8.GetString(buffer, 0, r); ShowMsg(socketSend.RemoteEndPoint + ":" + str); } catch { } } } void ShowMsg(string str) { richTextBox1.AppendText(str+"\r\n"); } private void Form1_Load(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; } /// <summary> /// 服务器给客户端发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { try { if(richTextBox2.Text.Trim() == "") { MessageBox.Show("当前无发送内容"); return; } string str = richTextBox2.Text.Trim(); byte[] buffer = Encoding.UTF8.GetBytes(str); List<byte> ls = new List<byte>(); ls.Add(0); ls.AddRange(buffer); byte[] newBuffer = ls.ToArray(); // 获得用户在下拉框中选中的IP地址 //socketSend.Send(buffer); string ip = comboBox1.SelectedItem.ToString(); dicSocket[ip].Send(newBuffer); richTextBox2.Clear(); } catch { } } OpenFileDialog ofd = new OpenFileDialog(); /// <summary> /// 选择要发送的文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// private void button2_Click(object sender, EventArgs e) { try { ofd.InitialDirectory = @"D:\"; ofd.Title = "请选择!"; ofd.Filter = "所有文件|*.*"; ofd.ShowDialog(); if (ofd.FileName != "") { textBox1.Text = ofd.FileName; } } catch { } } private void button3_Click(object sender, EventArgs e) { try { if (comboBox1.SelectedItem == null) { MessageBox.Show("请选择客户端IP"); return; } if (textBox1.Text.Trim() == "") { MessageBox.Show("当前无发送内容!"); return; } // 获得要发送文件的路径 string strPath = textBox1.Text.Trim(); using (FileStream fsRead = new FileStream(strPath, FileMode.OpenOrCreate, FileAccess.Read)) { #region 发送文件名给客户端 byte[] buffer1 = Encoding.UTF8.GetBytes(System.IO.Path.GetFileName(ofd.FileName)); List<byte> ls1 = new List<byte>(); ls1.Add(3); ls1.AddRange(buffer1); byte[] newBuffer1 = ls1.ToArray(); dicSocket[comboBox1.SelectedItem.ToString()].Send(newBuffer1); #endregion #region 发送文件给客户端 byte[] buffer = new byte[1024 * 1024 * 3]; int r = fsRead.Read(buffer, 0, buffer.Length); List<byte> ls = new List<byte>(); ls.Add(1); ls.AddRange(buffer); byte[] newBuffer = ls.ToArray(); dicSocket[comboBox1.SelectedItem.ToString()].Send(newBuffer, 0, r + 1, SocketFlags.None); #endregion richTextBox2.Clear(); } } catch { } } /// <summary> /// 发送震动 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button4_Click(object sender, EventArgs e) { try { byte[] buffer = new byte[1]; buffer[0] = 2; dicSocket[comboBox1.SelectedItem.ToString()].Send(buffer); } catch { } } } }
参考博客(加了几个自我定义的功能,如服务器端判断客户端是否断开)
https://www.cnblogs.com/zzp0320/p/7909828.html