scoket通信窗体(加强、线程)
如果 客户端 连接不上 服务端,可能是没有开Telnet;Windows10没有telnet服务器端了,还有可能是IPv4写错了
IPV4是有可能发生变化的
想要安装Telnet可以打开windows的控制面板 然后打开"程序和功能" 然后点击"启动或关闭windows功能" 最后找到"telnet客户端和telnet服务器端"
1 namespace _Server_服务端_窗体_ 2 { 3 public partial class Form1 : Form 4 { 5 6 public Form1() 7 { 8 InitializeComponent(); 9 } 10 //将负责监听和通信的Socket写到方法外面,方便别的方法调用 11 Socket socketWatch; 12 Socket socketSend; 13 14 //用于存储IP地址和负责跟客户端通信的Socket 15 readonly Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>(); 16 17 18 private void BtnStart_Click(object sender, EventArgs e) 19 { 20 //创建一个负责监听“Socket” 21 socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 22 //建立IP地址和端口号 对象 23 IPAddress iP = IPAddress.Any;//这可以动态的获得一个IPV4,不用写死,所以txtscoket这个文本框是没用的 24 //txtPort是个文本框 25 IPEndPoint iPEnd = new IPEndPoint(iP, Convert.ToInt32(txtPort.Text)); 26 //让负责监听的Socket绑定IP地址和端口号 27 socketWatch.Bind(iPEnd); 28 Show("监听成功"); 29 //设置监听的队列 30 socketWatch.Listen(10); 31 //负责监听的Socket 来接收客户端的连接 32 //开启一个新的线程来执行Listen方法 33 Thread th = new Thread(Listen); 34 th.IsBackground = true; 35 th.Start(socketWatch); 36 37 } 38 void Show(string str) 39 { 40 //txtLog:文本框 41 txtLog.AppendText(str + "\r\n"); 42 //txtLog.Text(); 会覆盖前一个文本 43 //txtLog.Text = str + "\r\n"; 44 } 45 ///_Server_服务端_窗体_46 /// 监听客户端的连接 并创建与之通信的Socket 47 /// 48 /// 49 void Listen(object o) 50 { 51 Socket socketWatch = o as Socket; 52 while (true) 53 { 54 try 55 { 56 //通过Accept()这个方法创建负责和客户端通信的Socket 57 socketSend = socketWatch.Accept(); 58 //将远程客户端的IP地址和端口号存储到ComboBox(下拉列表)中 59 cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString()); 60 61 //再将IP地址和IP地址所对应得Socket添加到键值对集合中 62 //RemoteEndPoint:获得远程终结点(也就是IPv4) 63 dicSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend); 64 65 Show(socketSend.RemoteEndPoint.ToString() + "连接成功"); 66 67 //开一个新线程不停的接受客户端发来的消息 68 Thread th2 = new Thread(Rec); 69 th2.IsBackground = true; 70 th2.Start(socketSend); 71 } 72 catch 73 { 74 75 } 76 } 77 } 78 79 80 /// 81 /// 不停的接收客户端发来的数据 82 /// 83 /// 84 void Rec(object o) 85 { 86 Socket socketSend = o as Socket; 87 while (true) 88 { 89 try 90 { 91 //当客户端连接成功后,服务端就可以接收客户端发来的数据 92 byte[] vs = new byte[1024 * 1024 * 2]; 93 //服务端实际接收到是字节数组 94 //r:是实际接受的有效字节数 95 int r = socketSend.Receive(vs); 96 //当r=0是接收到的实际数据为空; 97 //表示客户端下线了,然后跳出循环 98 if (r == 0) 99 { 100 break; 101 } 102 103 //将字节数组转换成字符串 104 string str = Encoding.UTF8.GetString(vs, 0, r); 105 Show(socketSend.RemoteEndPoint.ToString() + ":" + str); 106 } 107 catch 108 { 109 //socketSend.Receive(vs);//当客户端掉线时,且没有断开连接,Receive();函数会一直等客户端发消息,从而报错, 110 // 在没有客户端掉线,没有发消息的,Receive()方法会一直等,不会有返回值,而是直接报错 111 //当客户端掉线并没有断开连接,上面的if语句将不会执行,直接跳到catch语句内,当catch语句块内没有语句时,将一直循环while语句块。 112 Console.WriteLine("有问题!!"); 113 } 114 } 115 } 116 117 private void Form1_Load(object sender, EventArgs e) 118 { 119 //在程序加载的时候 取消跨线程的检查 120 Control.CheckForIllegalCrossThreadCalls = false;//这种方式不是好方法,有好方法,用异步委托 121 } 122 123 /// 124 /// 服务端给客户端发送文字消息 125 /// 126 /// 127 /// 128 private void BtnSend_Click(object sender, EventArgs e) 129 { 130 //txtMsg:文本框 131 byte[] vs = Encoding.UTF8.GetBytes(txtMsg.Text); 132 //将字节数组前面加“0”表示为发的是文本文件,后将新的字节数组发送 133 List<byte> list = new List<byte>(); 134 list.Add(0); 135 list.AddRange(vs); 136 //将集合转成字节数组 137 byte[] vs1 = list.ToArray(); 138 139 //获得在下拉框中选中的IP地址 140 //cboUsers:下拉菜单 141 string IP = cboUsers.SelectedItem.ToString(); 142 dicSocket[IP].Send(vs1); 143 } 144 145 private void BtnSelect_Click(object sender, EventArgs e) 146 { 147 // OpenFileDialog:显示一个标准对话框,提示用户打开文件。 148 OpenFileDialog ofd = new OpenFileDialog(); 149 ofd.InitialDirectory = @"C:\Users\顾守\OneDrive\桌面"; 150 ofd.Title = "请选择要发的文件"; 151 ofd.Filter = "文本文件|*.txt|音乐文件|*.mp3|图片文件1|*.jpg|所有文件|*.*"; 152 ofd.ShowDialog(); 153 //获得选中文件的路径 154 //txtPath:文本框 155 txtPath.Text = ofd.FileName; 156 } 157 /// 158 /// 发文件 159 /// 160 /// 161 /// 162 private void BtnSendFile_Click(object sender, EventArgs e) 163 { 164 using (FileStream file = new FileStream(txtPath.Text, FileMode.Open, FileAccess.ReadWrite)) 165 { 166 byte[] vs = new byte[file.Length]; 167 //实际读取到的有效字节数 168 int r = file.Read(vs, 0, vs.Length); 169 List<byte> list = new List<byte>(); 170 list.Add(1); 171 list.AddRange(vs); 172 byte[] vs1 = list.ToArray(); 173 174 //获得用户选择的IP地址 175 //cboUsers:下拉菜单 176 string ip = cboUsers.Items.ToString(); 177 //发送 178 //用于存储IP地址和负责跟客户端通信的Socket;再开头定义的 179 //Send:将数据发送到连接的 socket 180 dicSocket[ip].Send(vs1); 181 } 182 } 183 184 /// 185 /// 发震动 186 /// 187 /// 188 /// 189 private void BtnZD_Click(object sender, EventArgs e) 190 { 191 byte[] vs = new byte[1]; 192 vs[0] = 2; 193 //获得用户选择的IP地址 194 //cboUsers:下拉菜单 195 string ip = cboUsers.SelectedItem.ToString(); 196 dicSocket[ip].Send(vs); 197 } 198 } 199 }
socketSend.Receive(vs);//当客户端掉线时,且没有断开连接,Receive();函数会一直等客户端发消息,从而报错,
在没有客户端掉线,没有发消息的,Receive()方法会一直等,不会有返回值,而是直接报错
解决的办法是:在客户端关闭时,要
socket.Shutdown(SocketShutdown.Both);//禁止发送和接受的socket,也就是断开连接
socket.Close();//关闭连接和释放所有的资源
socket.Dispose();//释放socket这个类的资源
1 namespace _Client_客户端_窗体_ 2 { 3 public partial class Form1 : Form 4 { 5 public Form1() 6 { 7 InitializeComponent(); 8 } 9 Socket socket; 10 private void BtnStart_Click(object sender, EventArgs e) 11 { 12 try 13 { 14 //在客户端创建一个负责跟服务端通信 使用的 Socket 15 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 16 //获得要连接的服务器的IP地址 17 IPAddress iP = IPAddress.Parse(txtServer.Text);//txtServer:文本框 ——>TextBox 18 //获得要连接的服务器的端口号 19 IPEndPoint iPEnd = new IPEndPoint(iP, int.Parse(txtPort.Text));//txtPort:文本框 ——>TextBox 20 //客户端负责通信的Socket去连接服务端的IP地址和端口号 21 socket.Connect(iPEnd); 22 ShowMsg("连接成功"); 23 24 //设置线程来负责 25 Thread th = new Thread(Rec) 26 { 27 IsBackground = true 28 }; 29 th.Start(); 30 } 31 catch 32 { 33 34 } 35 } 36 ///_Client_客户端_窗体_37 /// 38 /// 39 void Rec() 40 { 41 while (true) 42 { 43 try 44 { 45 //客户端接受服务端发来的消息 46 byte[] vs = new byte[1024 * 1024 * 2]; 47 //接受到的有效的字节数 48 int r = socket.Receive(vs); 49 byte b = vs[0]; 50 //发送文本消息 51 if (b == 0) 52 { 53 string str = Encoding.UTF8.GetString(vs, 1, r - 1); 54 txtLog.AppendText(str); 55 } 56 //发送文件消息 57 else if (b == 1) 58 { 59 //SaveFileDialog:提示用户选择保存文件的位置 60 SaveFileDialog sfd = new SaveFileDialog(); 61 sfd.InitialDirectory = @"C:\Users\顾守\OneDrive\桌面"; 62 sfd.Filter = "文本文件|*.txt|图片文件|*.jpg|音乐文件|*.mp3|所有文件|*.*"; 63 sfd.Title = "请选择保存路径"; 64 sfd.ShowDialog(); 65 string str = sfd.FileName; 66 using (FileStream file = new FileStream(str, FileMode.OpenOrCreate, FileAccess.ReadWrite)) 67 { 68 file.Write(vs, 1, r - 1); 69 } 70 MessageBox.Show("保存成功"); 71 } 72 //发震动 73 else if (b == 2) 74 { 75 ZD(); 76 } 77 } 78 catch 79 { 80 } 81 } 82 } 83 /// 84 /// 让窗体震动 85 /// 86 void ZD() 87 { 88 for (int i = 0; i < 200; i++) 89 { 90 //Location:获取或设置以屏幕坐标表示的代表 System.Windows.Forms.Form 左上角的 System.Drawing.Point 91 //Point:新实例初始化 System.Drawing.Point 类的指定坐标 92 this.Location = new Point(200, 200); 93 this.Location = new Point(500, 500); 94 } 95 96 } 97 98 99 void ShowMsg(string str) 100 { 101 txtLog.AppendText(str + "\r\n");//txtLog:文本框 ——>TextBox 102 } 103 104 /// 105 /// 向服务端发消息 106 /// 107 /// 108 /// 109 private void BtnSend_Click(object sender, EventArgs e) 110 { 111 string str = txtMsg.Text;//txtMsg:文本框 ——>TextBox 112 byte[] vs = Encoding.UTF8.GetBytes(str); 113 socket.Send(vs); 114 } 115 116 117 private void Form1_Load(object sender, EventArgs e) 118 { 119 //在程序加载的时候 取消跨线程的检查 120 Control.CheckForIllegalCrossThreadCalls = false;////这种方式不是好方法,有好方法,用异步委托 121 } 122 } 123 }