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         /// 
 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 }
_Server_服务端_窗体_

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         /// 
 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 }
_Client_客户端_窗体_
C