花了很久时间,终于把这个搞完了,虽然不是很完美,但是自己感觉还是可以将就用的。
主要功能:
1、实现客户端服务器一对一聊天以及传输文件。
2、实现群聊功能。
3、每一个form2里面用子窗体显示所对应父窗体传输文件进度条。
4、在线列表能够及时显示当前在线客户以及删除掉线的客户端。
需要注意一点的就是父窗体操作子窗体需要将子窗体上的控件属性设置为public类型,比如子窗体名字叫Form2.cs,你需要操作子窗体的label1方法,private System.Windows.Forms.Label label1,将Form2.cs下的Form2.Designer.cs相应控件申明为public,也就是这样了public System.Windows.Forms.Label label1
因为具有一定保护级别父窗体就不能访问了。
服务器代码以及界面:
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.Sockets; using System.Net; using System.Threading; using System.IO; using System.Threading; namespace ServerForm { public partial class Form1 : Form { private Socket ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); private Dictionary<string, Socket> ClientInformation = new Dictionary<string, Socket>();//一个字典 public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; richTextBox1.Multiline = true; //将Multiline属性设置为true,实现显示多行 richTextBox1.ScrollBars = RichTextBoxScrollBars.Vertical; richTextBox2.Multiline = true; //将Multiline属性设置为true,实现显示多行 richTextBox2.ScrollBars = RichTextBoxScrollBars.Vertical; //设 //richTextBox3.Multiline = true; //将Multiline属性设置为true,实现显示多行 //richTextBox3.ScrollBars = RichTextBoxScrollBars.Vertical; //设 //在多线程程序中,新创建的线程不能访问UI线程创建的窗口控件 //如果需要访问窗口控件则可以如此设置 } private void Form1_Load(object sender, EventArgs e) { ; } private void label1_Click(object sender, EventArgs e)//ip { } private void label2_Click(object sender, EventArgs e)//Port { } private void label3_Click(object sender, EventArgs e)//在线列表 { } private void richTextBox1_TextChanged(object sender, EventArgs e)//显示客户端之间/客户端消息 { } private void richTextBox2_TextChanged(object sender, EventArgs e)//显示连接成功或者掉线的客户端 { } private void textBox1_TextChanged(object sender, EventArgs e)//IP { } private void textBox2_TextChanged(object sender, EventArgs e)//Port { } private void button1_Click(object sender, EventArgs e)//启动服务 { try { int Port = Convert.ToInt32(textBox2.Text); IPAddress IP = IPAddress.Parse((string)textBox1.Text); ServerSocket.Bind(new IPEndPoint(IP, Port)); ServerSocket.Listen(20); richTextBox2.Text += "启动监听成功!\r\n"; richTextBox2.Text += "监听本地" + ServerSocket.LocalEndPoint.ToString() + "成功\r\n"; Thread ThreadListen = new Thread(ListenConnection); ThreadListen.IsBackground = true; ThreadListen.Start(); } catch (Exception ex) { richTextBox2.Text += "监听异常!!!\r\n"; ServerSocket.Shutdown(SocketShutdown.Both); ServerSocket.Close(); } } private void ListenConnection() { Socket ConnectionSocket = null; while (true) { try { ConnectionSocket = ServerSocket.Accept(); } catch (Exception ex) { richTextBox2.Text += "监听套接字异常" + ex.Message; break; } //获取客户端端口号和IP IPAddress ClientIP = (ConnectionSocket.RemoteEndPoint as IPEndPoint).Address; int ClientPort = (ConnectionSocket.RemoteEndPoint as IPEndPoint).Port; string SendMessage = "本地IP:" + ClientIP + ",本地端口:" + ClientPort.ToString(); ConnectionSocket.Send(Encoding.UTF8.GetBytes(SendMessage)); string remotePoint = ConnectionSocket.RemoteEndPoint.ToString(); richTextBox2.Text += "成功与客户端" + remotePoint + "建立连接\r\n"; listBox1.Items.Add(remotePoint); ClientInformation.Add(remotePoint, ConnectionSocket); ParameterizedThreadStart pts = new ParameterizedThreadStart(ReceiveMessage); Thread thread = new Thread(pts); thread.IsBackground = true;//设置后台线程 thread.Start(ConnectionSocket); ClientThread.Add(remotePoint, thread); } } private void ReceiveMessage(Object SocketClient)///接收消息 { Socket ReceiveSocket = (Socket)SocketClient; long FileLength = 0; while (true) { int ReceiveLength = 0; byte[] result = new byte[1024 * 1024 * 10]; try { IPAddress ClientIP = (ReceiveSocket.RemoteEndPoint as IPEndPoint).Address; int ClientPort = (ReceiveSocket.RemoteEndPoint as IPEndPoint).Port; ReceiveLength = ReceiveSocket.Receive(result); string str = ReceiveSocket.RemoteEndPoint.ToString(); if (result[0] == 0)//接收消息 { string ReceiveMessage = Encoding.UTF8.GetString(result, 1, ReceiveLength - 1); richTextBox1.Text += ReceiveMessage; if (ClientInformation.Count == 1) continue;//只有一个客户端 List<string> test = new List<string>(ClientInformation.Keys); for (int i = 0; i < ClientInformation.Count; i++) {//将接收到的消息群发出去,即所谓的群聊了 Socket socket = ClientInformation[test[i]]; string s = ReceiveSocket.RemoteEndPoint.ToString(); if (test[i] != s) { richTextBox1.Text += DateTime.Now + "\r\n" + "客户端" + str + "向客户端" + test[i] + "发送消息:\r\n"; byte[] arrMsg = Encoding.UTF8.GetBytes(ReceiveMessage); byte[] SendMsg = new byte[arrMsg.Length + 1]; SendMsg[0] = 0; Buffer.BlockCopy(arrMsg, 0, SendMsg, 1, arrMsg.Length); socket.Send(SendMsg); } } } if (result[0] == 1)//接收文件 { try { richTextBox1.Text += "接收客户端:" + ReceiveSocket.RemoteEndPoint.ToString() + "时间:" + DateTime.Now.ToString() + "\r\n" + "文件:\r\n"; SaveFileDialog sfd = new SaveFileDialog(); if (sfd.ShowDialog(this) == DialogResult.OK) { long Rlength = 0; bool flag = true; int rec = 0; string fileSavePath = sfd.FileName; richTextBox1.Text += "文件总长度为:" + FileLength.ToString() + "\r\n"; using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)) { while (FileLength > Rlength) { if (flag) { fs.Write(result, 1, ReceiveLength - 1); fs.Flush(); Rlength += (ReceiveLength - 1); flag = false; } else { rec = ReceiveSocket.Receive(result); fs.Write(result, 0, rec); fs.Flush(); Rlength += rec; } } richTextBox1.Text += "文件保存成功:" + fileSavePath + "\r\n"; fs.Close(); } } } catch (Exception ex) { MessageBox.Show("服务器出现异常!"); } } if (result[0] == 2)//接收文件信息和长度 { string fileNameWithLength = Encoding.UTF8.GetString(result, 1, ReceiveLength - 1); //recStr = fileNameWithLength.Split('-').First(); FileLength = Convert.ToInt64(fileNameWithLength.Split('-').Last()); richTextBox1.Text += "FileLength=" + FileLength.ToString() + "\r\n"; } } catch (Exception ex) { richTextBox2.Text += "监听出现异常!\r\n"; richTextBox2.Text += "客户端" + ReceiveSocket.RemoteEndPoint + "已经连接中断" + "\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n"; listBox1.Items.Remove(ReceiveSocket.RemoteEndPoint.ToString());//从listbox中移除断开连接的客户端 string s = ReceiveSocket.RemoteEndPoint.ToString(); ClientInformation.Remove(s); ReceiveSocket.Shutdown(SocketShutdown.Both); ReceiveSocket.Close(); break; } } } private void textBox3_TextChanged(object sender, EventArgs e)//选择文件 { ; } private void button4_Click(object sender, EventArgs e)//发送文件 { if (string.IsNullOrEmpty(textBox3.Text)) { MessageBox.Show("请选择你要发送的文件!!!"); } else { Form2 a = new Form2(); long TotalLength1 = new FileInfo(textBox3.Text).Length;//文件总长度 a.progressBar1.Value = 0;//设置进度条的当前位置为0 a.progressBar1.Minimum = 0; //设置进度条的最小值为0 a.progressBar1.Maximum = Convert.ToInt32(TotalLength1);//设置进度条的最大值 string fileName = Path.GetFileName(textBox3.Text);//文件名 string fileExtension = Path.GetExtension(textBox3.Text);//扩展名字||后缀 string str = string.Format("{0}-{1}", fileExtension, TotalLength1); byte[] arr = Encoding.UTF8.GetBytes(str); byte[] arrSend = new byte[arr.Length + 1]; arrSend[0] = 2;//发送文件信息 Buffer.BlockCopy(arr, 0, arrSend, 1, arr.Length); foreach (string str1 in ClientInformation.Keys) { ClientInformation[str1].Send(arrSend); break; } byte[] arrFile = new byte[1024 * 1024 * 10]; using (FileStream fs = new FileStream(textBox3.Text, FileMode.Open, FileAccess.Read)) { long TotalLength = fs.Length;//文件总长度 richTextBox1.Text += "文件总长度" + TotalLength.ToString() + "\r\n"; Buffer.BlockCopy(arr, 0, arrSend, 1, arr.Length); foreach (string str1 in ClientInformation.Keys) { ClientInformation[str1].Send(arrSend);//发送文件名和长度 int FileLength = 0;//每次读取长度 long sendFileLength = 0; bool flag = true; long num1 = 0; while ((TotalLength > sendFileLength) && (FileLength = fs.Read(arrFile, 0, arrFile.Length)) > 0) { sendFileLength += FileLength; if (flag) { byte[] arrFileSend = new byte[FileLength + 1]; arrFileSend[0] = 1; // 用来表示发送的是文件数据 Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, FileLength); ClientInformation[str1].Send(arrFileSend, 0, FileLength + 1, SocketFlags.None); flag = false; } else { ClientInformation[str1].Send(arrFile, 0, FileLength, SocketFlags.None); } a.progressBar1.Value += FileLength; num1 += FileLength * 100; long num2 = a.progressBar1.Maximum;//这里可能超范围,必要时使用高精度 long num = num1 / num2; a.label1.Text = (num1/num2).ToString() + "%"; a.Show(); Application.DoEvents();//重点,必须加上,否则父子窗体都假死 } if(a.progressBar1.Value== TotalLength) { MessageBox.Show("文件发送完毕!!!"); a.Close(); textBox3.Clear(); fs.Close(); break; } else { MessageBox.Show("文件发送失败!!!"); a.Close(); textBox3.Clear(); fs.Close(); break; } } } } } private void button2_Click(object sender, EventArgs e)//选择文件 { OpenFileDialog ofd = new OpenFileDialog(); ofd.InitialDirectory = "D:\\"; if (ofd.ShowDialog() == DialogResult.OK) { textBox3.Text += ofd.FileName; } } private void button3_Click(object sender, EventArgs e)//发送消息 { richTextBox1.Text += "向客户端发送消息:\r\n"; string sb = textBox4.Text; richTextBox1.Text += sb + "\r\n"; string SendMessage = "接收服务器" + ServerSocket.LocalEndPoint.ToString() + "消息:" + DateTime.Now + "\r\n" + sb + "\r\n"; List<string> test = new List<string>(ClientInformation.Keys); for (int i = 0; i < ClientInformation.Count; i++) {//给每个在线客户端发送消息 Socket socket = ClientInformation[test[i]]; byte[] arrMsg = Encoding.UTF8.GetBytes(SendMessage); byte[] SendMsg = new byte[arrMsg.Length + 1]; SendMsg[0] = 0; Buffer.BlockCopy(arrMsg, 0, SendMsg, 1, arrMsg.Length); socket.Send(SendMsg); } textBox4.Clear(); } private void textBox4_TextChanged(object sender, EventArgs e)//发送消息 { } private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { } } }
form2代码:
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; namespace ServerForm { public partial class Form2 : Form { public Form2() { InitializeComponent(); } private void progressBar1_Click(object sender, EventArgs e) { } private void label1_Click(object sender, EventArgs e) { } } }
服务器界面
form1:form2界面:隐藏右上边那个X就是将窗体属性的ControlBox状态设置为True,隐藏标题将窗体的FormBorderStyle状态设置为None
客户端代码:
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.Sockets; using System.Net; using System.Threading; using System.IO; namespace ClientForm { public partial class Form1 : Form { private object locker = new object(); private Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; richTextBox1.Multiline = true; //将Multiline属性设置为true,实现显示多行 richTextBox1.ScrollBars = RichTextBoxScrollBars.Vertical; richTextBox2.Multiline = true; //将Multiline属性设置为true,实现显示多行 richTextBox2.ScrollBars = RichTextBoxScrollBars.Vertical; //设 } private void Form1_Load(object sender, EventArgs e) { ; } private void textBox1_TextChanged(object sender, EventArgs e)//输入消息 { string str = Console.ReadLine(); textBox1.Text += str; } private void textBox2_TextChanged(object sender, EventArgs e)//ip { ; } private void textBox3_TextChanged(object sender, EventArgs e)//port { ; } private void button4_Click(object sender, EventArgs e)//发送文件 { if (string.IsNullOrEmpty(textBox5.Text)) { MessageBox.Show("选择要发送的文件!!!"); } else { //采用文件流方式打开文件 using (FileStream fs = new FileStream(textBox5.Text, FileMode.Open)) { long TotalLength = fs.Length;//文件总长度 Form2 a = new Form2(); a.progressBar1.Value = 0;//设置进度条的当前位置为0 a.progressBar1.Minimum = 0; //设置进度条的最小值为0 a.progressBar1.Maximum = Convert.ToInt32(TotalLength);//设置进度条的最大值 richTextBox1.Text += "文件总长度为:" + TotalLength.ToString()+"\r\n"; string fileName = Path.GetFileName(textBox5.Text);//文件名 string fileExtension = Path.GetExtension(textBox5.Text);//扩展名 string str = string.Format("{0}-{1}", fileName, TotalLength); byte[] arr = Encoding.UTF8.GetBytes(str); byte[] arrSend = new byte[arr.Length + 1]; Buffer.BlockCopy(arr, 0, arrSend, 1, arr.Length); arrSend[0] = 2;//发送文件信息 ClientSocket.Send(arrSend); byte[] arrFile = new byte[1024 * 1024 * 10]; int FileLength=0;//将要发送的文件读到缓冲区 long SendFileLength = 0; bool flag = true; long num1 = 0; while(TotalLength> SendFileLength&& (FileLength = fs.Read(arrFile, 0, arrFile.Length))>0) { SendFileLength+=FileLength; if (flag) { byte[] arrFileSend = new byte[FileLength + 1]; arrFileSend[0] = 1; Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, FileLength); ClientSocket.Send(arrFileSend,0,FileLength+1, SocketFlags.None); flag = false; } else { ClientSocket.Send(arrFile, 0, FileLength, SocketFlags.None); } a.progressBar1.Value += FileLength; num1 += FileLength*100; long num2 = TotalLength; long num = num1 / num2; a.label1.Text = (num1 / num2).ToString() + "%"; a.Show(); Application.DoEvents();//重点,必须加上,否则父子窗体都假死 } try { if (a.progressBar1.Value == a.progressBar1.Maximum) { MessageBox.Show("文件发送完毕!!!"); a.Close(); textBox5.Clear(); fs.Close(); } } catch { MessageBox.Show("文件发送失败!"); a.Close(); textBox5.Clear(); fs.Close(); } } } } private void button3_Click(object sender, EventArgs e)//选择文件 { OpenFileDialog ofd = new OpenFileDialog(); ofd.InitialDirectory = "D:\\"; if (ofd.ShowDialog() == DialogResult.OK) { textBox5.Text += ofd.FileName; } } private void textBox5_TextChanged(object sender, EventArgs e)//选择文件 { ; } private void button1_Click(object sender, EventArgs e)//发送消息 { try { //Thread.Sleep(2000); richTextBox1.Text += "向服务器发送消息:\r\n"; richTextBox1.Text += textBox1.Text + "\r\n"; string sb = textBox1.Text; string Client = ClientSocket.RemoteEndPoint.ToString(); string SendMessage = "接收客户端" + Client + "消息:" + DateTime.Now + "\r\n" + sb + "\r\n"; byte[] result1 = Encoding.UTF8.GetBytes(SendMessage); byte[] result = new byte[result1.Length + 1]; result[0] = 0; Buffer.BlockCopy(result1, 0, result, 1, result1.Length); ClientSocket.Send(result); textBox1.Clear(); } catch (Exception ex) { richTextBox1.Text += "发送消息失败,服务器可能已经关闭!\r\n"; ClientSocket.Shutdown(SocketShutdown.Both); ClientSocket.Close(); } } private void button2_Click(object sender, EventArgs e)//连接服务器 { int Port = Convert.ToInt32(textBox3.Text); IPAddress IP = IPAddress.Parse((string)textBox2.Text); try { ClientSocket.Connect(new IPEndPoint(IP, Port)); richTextBox2.Text += "连接服务器成功!\r\n"; Thread thread = new Thread(ReceiveMessage); thread.IsBackground = true; thread.Start(); } catch (Exception ex) { richTextBox2.Text += "连接服务器失败!\r\n"; return; } } private void label1_Click(object sender, EventArgs e) { ; } private void label2_Click(object sender, EventArgs e) { ; } private void richTextBox1_TextChanged(object sender, EventArgs e)//显示发送的消息 { ; } private void richTextBox2_TextChanged(object sender, EventArgs e)//显示接收的消息 { ; } private void ReceiveMessage() { long TotalLength = 0; while (true) { byte[] result = new byte[1024 * 1024 * 10]; int ReceiveLength = 0; try { ReceiveLength = ClientSocket.Receive(result); if (result[0] == 0)//表示接收到的是消息 { try { richTextBox2.Text += "接收服务器消息:\r\n"; string str = Encoding.UTF8.GetString(result, 1, ReceiveLength - 1); richTextBox2.Text += str + "\r\n"; } catch (Exception ex) { richTextBox2.Text += "接收消息失败!\r\n"; ClientSocket.Shutdown(SocketShutdown.Both); ClientSocket.Close(); break; } } if (result[0] == 2) { string fileNameWithLength = Encoding.UTF8.GetString(result, 1, ReceiveLength - 1); string str1 = fileNameWithLength.Split('-').First(); TotalLength = Convert.ToInt64(fileNameWithLength.Split('-').Last()); richTextBox2.Text += "接收服务器后缀名为:" + str1 + "的文件" + "\r\n"; } if (result[0] == 1)//表示接收到的是文件 { try { richTextBox1.Text += "文件总长度" + TotalLength.ToString() + "\r\n"; SaveFileDialog sfd = new SaveFileDialog(); if (sfd.ShowDialog(this) == DialogResult.OK) { string fileSavePath = sfd.FileName;//获取文件保存路径 long receiveLength = 0; bool flag = true; int rec = 0; using (FileStream fs = new FileStream(fileSavePath, FileMode.Create, FileAccess.Write)) { while (TotalLength > receiveLength) { if (flag) { fs.Write(result, 1, ReceiveLength - 1); fs.Flush(); receiveLength += ReceiveLength - 1; flag = false; } else { rec = ClientSocket.Receive(result); fs.Write(result, 0, rec); fs.Flush(); receiveLength += rec; } } richTextBox2.Text += "文件保存成功:" + " " + fileSavePath + "\r\n"; fs.Close(); } } } catch (Exception ex) { richTextBox2.Text += "文件保存失败!\r\n"; MessageBox.Show(ex.Message); ClientSocket.Shutdown(SocketShutdown.Both); ClientSocket.Close(); break; } } } catch(Exception ex) { MessageBox.Show("系统异常!"); break; } } } } }
客户端界面: