将之前的通信代码,以winform界面的形式写出来

winform应用程序,与控制台程序的代码没有太大的区别,最大的不同是将代码拆分成一个个小块,即一个个的方法,这样可以通过一个个的控件(按钮button等)去触发事件(方法)。 但是我感觉,不好的是,winform程序容易因为点击按钮的顺序,次数的不同,使程序出错,所以要多多的用try-catch。

客户端代码

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 using System.Net;
 10 using System.Net.Sockets;
 11 using System.Threading;
 12 
 13 namespace WindowsForms_客户端
 14 {
 15     public partial class Form1 : Form
 16     {
 17 
 18         byte[] data;
 19         string stringData;
 20         //创建服务器端IPEndPoint对象
 21         IPEndPoint Ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 125);
 22         Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 23 
 24         public Form1()
 25         {
 26             InitializeComponent();
 27         }
 28 
 29         /// <summary>
 30         /// 与服务器建立连接
 31         /// </summary>
 32         /// <param name="sender"></param>
 33         /// <param name="e"></param>
 34         private void buttonConnect_Click(object sender, EventArgs e)
 35         {
 36             try
 37             {
 38                 server.Connect(Ipep);
 39                 textState.AppendText("连接成功\n");
 40             }
 41             catch
 42             {
 43                 textState.AppendText("连接服务器失败\n");
 44                 MessageBox.Show("请先启动服务器,再启动客户端");
 45                 return;
 46             }
 47             Thread th = new Thread(Receive);
 48             th.IsBackground = true;
 49             th.Start();
 50         }
 51 
 52         /// <summary>
 53         /// 断开与服务器的连接
 54         /// </summary>
 55         /// <param name="sender"></param>
 56         /// <param name="e"></param>
 57         private void buttonBreak_Click(object sender, EventArgs e)
 58         {
 59             server.Shutdown(SocketShutdown.Both);
 60             server.Close();
 61             textState.AppendText("断开与服务器的连接\n");
 62         }
 63 
 64         
 65 
 66         /// <summary>
 67         /// 接收消息的方法  用的方法是ReceiveVarMessage 接收变长消息
 68         /// </summary>
 69         void Receive()
 70         {
 71             while (true)
 72             {
 73                 data = ReceiveVarMessage(server);
 74                 if (data.Length == 0)
 75                 {
 76                     break;
 77                 }
 78                 stringData = Encoding.UTF8.GetString(data, 0, data.Length);
 79                 textReceive.AppendText(stringData + "\n");
 80             }
 81 
 82 
 83             //while (true)
 84             //{
 85             //    //接收数据
 86             //    int receive = server.Receive(data);//receive是接收到的数据的长度 所以是int型  接收到的信息,存在data这个byte字节数组中
 87             //    if (receive == 0)
 88             //    {
 89             //        break;
 90             //    }
 91             //    stringData = Encoding.UTF8.GetString(data, 0, receive);
 92             //    textReceive.AppendText(stringData + "\n");
 93             //}
 94         }
 95 
 96         /// <summary>
 97         /// 跨线程访问
 98         /// </summary>
 99         /// <param name="sender"></param>
100         /// <param name="e"></param>
101         private void Form1_Load(object sender, EventArgs e)
102         {
103             Control.CheckForIllegalCrossThreadCalls = false;
104             textKp.Text = "0.4";
105             textKi.Text = "0.53";
106             textKd.Text = "0.1";
107             textKd.Focus();
108 
109         }
110 
111         /// <summary>
112         /// 发送消息到服务器端
113         /// </summary>
114         /// <param name="sender"></param>
115         /// <param name="e"></param>
116         private void buttonSend_Click(object sender, EventArgs e)
117         {
118             string str = textSend.Text;
119             data = System.Text.Encoding.UTF8.GetBytes(str);
120             SendVarMessage(server, data);
121         }
122 
123         private void textReceive_TextChanged(object sender, EventArgs e)
124         {
125 
126         }
127 
128         int i = 0;
129         /// <summary>
130         /// 客户端发送设定速度值 给服务器端
131         /// </summary>
132         /// <param name="sender"></param>
133         /// <param name="e"></param>
134         private void button1_Click(object sender, EventArgs e)
135         {
136             string speed = textSetspeed.Text;
137             try
138             {
139                 double dSpeed = Convert.ToDouble(speed);
140                 data = System.Text.Encoding.UTF8.GetBytes(speed);
141                 textSend.AppendText(""+(i+1)+"次发送的设定速度值是"+speed+"\n");
142                 SendVarMessage(server, data);
143                 //server.Send(data);
144                 i++;
145                 textSetspeed.Clear();
146                 textSetspeed.Focus();
147             }
148             catch
149             {
150                 MessageBox.Show("输入速度设定值不正确,请重新输入");
151                 textSend.AppendText(speed + "\n");
152                 textSetspeed.Clear();
153                 textSetspeed.Focus();
154             }
155         }
156 
157         /// <summary>
158         /// 发送变长消息方法
159         /// </summary>
160         /// <param name="s"></param>
161         /// <param name="msg"></param>
162         /// <returns></returns>
163         private static void SendVarMessage(Socket s, byte[] msg)
164         {
165             int offset = 0;
166             int sent;
167             int size = msg.Length;
168             int dataleft = size;
169             byte[] msgsize = new byte[2];
170 
171             //将消息的尺寸从整型转换成可以发送的字节型
172             //因为int型是占4个字节 所以msgsize是4个字节 后边是空字节
173             msgsize = BitConverter.GetBytes(size);
174 
175             //发送消息的长度信息
176             //之前总是乱码出错 客户端接收到的欢迎消息前两个字节是空 后边的两个字符er传送到第二次接收的字节数组中
177             //因此将er字符转换为int出错  这是因为之前在Send代码中,是将msgsize整个字节数组发送给客户端 所以导致第3 4个空格也发送
178             //导致发送的信息混乱 这两个空格使发送的信息都往后挪了两个位置  从而乱码
179             sent = s.Send(msgsize, 0, 2, SocketFlags.None);
180             while (dataleft > 0)
181             {
182                 int sent2 = s.Send(msg, offset, dataleft, SocketFlags.None);
183                 //设置偏移量
184                 offset += sent2;
185                 dataleft -= sent2;
186             }
187         }
188 
189         /// <summary>
190         /// 接收变长消息方法
191         /// </summary>
192         /// <param name="s"></param>
193         /// <returns>接收到的信息</returns>
194         private static byte[] ReceiveVarMessage(Socket s)//方法的返回值是字节数组 byte[] 存放的是接受到的信息
195         {
196             int offset = 0;
197             int recv;
198             byte[] msgsize = new byte[2];
199 
200             //接收2个字节大小的长度信息
201             recv = s.Receive(msgsize, 0, 2, 0);
202 
203             //将字节数组的消息长度转换为整型
204             int size = BitConverter.ToInt16(msgsize, 0);
205             int dataleft = size;
206             byte[] msg = new byte[size];
207             while (dataleft > 0)
208             {
209                 //接收数据
210                 recv = s.Receive(msg, offset, dataleft, 0);
211                 if (recv == 0)
212                 {
213                     break;
214                 }
215                 offset += recv;
216                 dataleft -= recv;
217             }
218             return msg;
219         }
220 
221         ///// <summary>
222         ///// 将kp参数的设置,发送给客户端     这里还没有客户端在线修改kp ki kd参数的功能 
223         ///// </summary>
224         ///// <param name="sender"></param>
225         ///// <param name="e"></param>
226         private void buttonChange_Click(object sender, EventArgs e)
227         {
228         //    data = System.Text.Encoding.UTF8.GetBytes(textKp.Text);
229         //    SendVarMessage(server, data);
230 
231         //    //data = System.Text.Encoding.UTF8.GetBytes(textKi.Text);
232         //    //SendVarMessage(server, data);
233 
234         //    //data = System.Text.Encoding.UTF8.GetBytes(textKd.Text);
235         //    //SendVarMessage(server, data);
236         }
237 
238         ///// <summary>
239         ///// 修改ki参数
240         ///// </summary>
241         ///// <param name="sender"></param>
242         ///// <param name="e"></param>
243         private void buttonChangeki_Click(object sender, EventArgs e)
244         {
245         //    data = System.Text.Encoding.UTF8.GetBytes(textKi.Text);
246         //    SendVarMessage(server, data);
247         }
248 
249         ///// <summary>
250         ///// 修改kd参数
251         ///// </summary>
252         ///// <param name="sender"></param>
253         ///// <param name="e"></param>
254         private void buttonChangekd_Click(object sender, EventArgs e)
255         {
256         //    data = System.Text.Encoding.UTF8.GetBytes(textKd.Text);
257         //    SendVarMessage(server, data);
258         }
259 
260 
261     }
262 }

服务器端代码:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 using System.Net;
 10 using System.Net.Sockets;
 11 using System.Threading;
 12 using System.Collections;
 13 
 14 namespace WindowsForms_服务器端
 15 {
 16     public partial class Form1 : Form
 17     {
 18         public Form1()
 19         {
 20             InitializeComponent();
 21         }
 22         double[] nums = new double[3];//存储3个偏差值e(k) e(k-1) e(k-2)
 23         double actual = 0;
 24         double set = 0;
 25         double kp;
 26         double ki;
 27         double kd;
 28         //定义一个空字节数组date作为数据缓冲区,用于缓冲流入和流出的信息
 29         byte[] date;
 30         static Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 31         static Socket client;
 32         ArrayList list = new ArrayList();//存储客户端发来的速度设定值
 33         ArrayList listOut = new ArrayList();//存储PID计算的实际速度值
 34         Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();//创建键值对,存储套接字的ip地址等信息
 35 
 36         Thread thConnect;
 37 
 38         /// <summary>
 39         /// 建立与客户端的连接
 40         /// </summary>
 41         /// <param name="sender"></param>
 42         /// <param name="e"></param>
 43         private void buttonConnect_Click(object sender, EventArgs e)
 44         {
 45             try
 46             {
 47                 IPEndPoint Ipep = new IPEndPoint(IPAddress.Any, 125);//指定地址和端口号
 48                 newsock.Bind(Ipep);
 49                 newsock.Listen(10);//置于监听状态
 50                 textState.Text = "等待客户端的连接\n";
 51                 thConnect = new Thread(Connect);
 52                 thConnect.IsBackground = true;
 53                 thConnect.Start();
 54                 //Receive();
 55             }
 56             catch
 57             { }
 58         }
 59 
 60         /// <summary>
 61         /// 不断接收从客户端发来消息的方法
 62         /// </summary>
 63         void Receive()
 64         {
 65             try
 66             {
 67                 while (true)
 68                 {
 69                     date = ReceiveVarMessage(client);
 70                     if (date.Length == 0)
 71                     {
 72                         break;
 73                     }
 74                     string str = Encoding.UTF8.GetString(date, 0, date.Length);
 75                     list.Add(str);
 76                     textReceive.AppendText(str + "\n");
 77                 }
 78             }
 79             catch
 80             { }
 81         }
 82 
 83         /// <summary>
 84         /// 服务器端与客户端连接的方法  使一个服务器可以与多个客户端连接
 85         /// </summary>
 86         private void Connect()
 87         {
 88             //接收来自客户端的接入尝试连接,并返回连接客户端的ip地址
 89             while (true)
 90             {
 91                 client = newsock.Accept();
 92                 IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
 93                 //返回客户端的ip地址和端口号
 94                 textState.AppendText("" + clientep.Address + "" + clientep.Port + "端口连接\n");
 95                 dicSocket.Add(clientep.ToString(), client);//将连接的客户端的IP地址添加在键值对集合中
 96                 comboBox.Items.Add(clientep);//将客户端的IP地址显示在下拉栏中
 97                 //Receive();
 98                 Thread thReceive = new Thread(Receive);//创建一个新线程 执行Receive()方法
 99                 thReceive.IsBackground = true;
100                 thReceive.Start();
101             }
102         }
103 
104         /// <summary>
105         /// 发送消息给客户端 需自己选择已连接的其中一个客户端
106         /// </summary>
107         /// <param name="sender"></param>
108         /// <param name="e"></param>
109         private void buttonSend_Click(object sender, EventArgs e)
110         {
111             try
112             {
113                 string str = textSend.Text;
114                 date = System.Text.Encoding.UTF8.GetBytes(str); //以字节数组的形式 将欢迎信息发送给客户端 注意发送与接收要用相同的编码格式UTF8 否则会乱码
115                 try
116                 {
117                     string ip = comboBox.SelectedItem.ToString();
118                     SendVarMessage(dicSocket[ip], date);
119                 }
120                 catch
121                 {
122                     MessageBox.Show("发送失败,请确认已选择一个客户端");
123                 }
124             }
125             catch
126             { }
127         }
128 
129 
130         /// <summary>
131         /// 断开与客户端的连接
132         /// </summary>
133         /// <param name="sender"></param>
134         /// <param name="e"></param>
135         private void buttonBreak_Click(object sender, EventArgs e)
136         {
137             try
138             {
139                 client.Close();
140                 newsock.Close();
141                 textState.AppendText("断开连接\n");
142             }
143             catch { }
144         }
145 
146         /// <summary>
147         /// 跨线程访问
148         /// </summary>
149         /// <param name="sender"></param>
150         /// <param name="e"></param>
151         private void Form1_Load(object sender, EventArgs e)
152         {
153             Control.CheckForIllegalCrossThreadCalls = false;
154         }
155 
156         private void textState_TextChanged(object sender, EventArgs e)
157         {
158 
159         }
160 
161         private void textReceive_TextChanged(object sender, EventArgs e)
162         {
163 
164         }
165 
166         /// <summary>
167         /// 开始进行PID计算
168         /// </summary>
169         /// <param name="sender"></param>
170         /// <param name="e"></param>
171         private void button1_Click(object sender, EventArgs e)
172         {
173             //Thread thKp = new Thread(GetKp);
174             //thKp.IsBackground = true;
175             //thKp.Start();
176             ////date=ReceiveVarMessage(client);
177             ////string strKp = Encoding.UTF8.GetString(date,0,date.Length);
178             ////kp = Convert.ToDouble(strKp);
179 
180             //Thread thKi = new Thread(GetKi);
181             //thKi.IsBackground = true;
182             //thKi.Start();
183             ////date = ReceiveVarMessage(client);
184             ////string strKi = Encoding.UTF8.GetString(date, 0, date.Length);
185             ////ki = Convert.ToDouble(strKi);
186 
187             //Thread thKd = new Thread(GetKd);
188             //thKd.IsBackground = true;
189             //thKd.Start();
190             ////date = ReceiveVarMessage(client);
191             ////string strKd = Encoding.UTF8.GetString(date);
192             ////kd = Convert.ToDouble(strKd);
193 
194             int n = list.Count;
195             int i = 0;
196             while (i < n)
197             {
198                 set = double.Parse(list[i].ToString());
199                 nums[0] = set - actual;
200                 double increase = 0.4* (nums[0] - nums[1]) + 0.53 * nums[0] + 0.1 * (nums[0] - 2 * nums[1] + nums[2]);
201                 actual += increase;
202                 listOut.Add(actual);//将每次的实际速度值  添加到集合中
203                 textActualspeed.AppendText("" + (i + 1) + "次的实际输出速度是" + actual + "\n"); //输出实际的速度值 成功!
204                 nums[1] = nums[0];
205                 nums[2] = nums[1];
206                 i++;
207             }
208         }
209 
210         ///// <summary>
211         ///// 得到客户端传来的Kp参数
212         ///// </summary>
213         //private void GetKp()
214         //{
215         //    date = ReceiveVarMessage(client);
216         //    string strKp = Encoding.UTF8.GetString(date, 0, date.Length);
217         //    kp = Convert.ToDouble(strKp);
218         //}
219 
220         ///// <summary>
221         ///// 得到客户端传来的Ki参数
222         ///// </summary>
223         //private void GetKi()
224         //{
225         //    date = ReceiveVarMessage(client);
226         //    string strKi = Encoding.UTF8.GetString(date, 0, date.Length);
227         //    ki = Convert.ToDouble(strKi);
228         //}
229 
230         ///// <summary>
231         ///// 得到客户端传来的Kd参数
232         ///// </summary>
233         //private void GetKd()
234         //{
235         //    date = ReceiveVarMessage(client);
236         //    string strKd = Encoding.UTF8.GetString(date, 0, date.Length);
237         //    kd = Convert.ToDouble(strKd);
238         //}
239 
240         /// <summary>
241         /// 发送变长消息方法
242         /// </summary>
243         /// <param name="s"></param>
244         /// <param name="msg"></param>
245         /// <returns></returns>
246         private static void SendVarMessage(Socket s, byte[] msg)
247         {
248             int offset = 0;
249             int sent;
250             int size = msg.Length;
251             int dataleft = size;
252             byte[] msgsize = new byte[2];
253 
254             //将消息的尺寸从整型转换成可以发送的字节型
255             //因为int型是占4个字节 所以msgsize是4个字节 后边是空字节
256             msgsize = BitConverter.GetBytes(size);
257 
258             //发送消息的长度信息
259             //之前总是乱码出错 客户端接收到的欢迎消息前两个字节是空 后边的两个字符er传送到第二次接收的字节数组中
260             //因此将er字符转换为int出错  这是因为之前在Send代码中,是将msgsize整个字节数组发送给客户端 所以导致第3 4个空格也发送
261             //导致发送的信息混乱 这两个空格使发送的信息都往后挪了两个位置  从而乱码
262             sent = s.Send(msgsize, 0, 2, SocketFlags.None);
263             while (dataleft > 0)
264             {
265                 int sent2 = s.Send(msg, offset, dataleft, SocketFlags.None);
266                 //设置偏移量
267                 offset += sent2;
268                 dataleft -= sent2;
269             }
270             //return dataleft;
271         }
272 
273         /// <summary>
274         /// 接收变长消息方法
275         /// </summary>
276         /// <param name="s"></param>
277         /// <returns>接收到的信息</returns>
278         private static byte[] ReceiveVarMessage(object o)//方法的返回值是字节数组 byte[] 存放的是接受到的信息
279         {
280             Socket s = o as Socket;
281             int offset = 0;
282             int recv;
283             byte[] msgsize = new byte[2];
284 
285             //接收2个字节大小的长度信息
286             recv = s.Receive(msgsize, 0, 2, 0);
287 
288             //将字节数组的消息长度转换为整型
289             int size = BitConverter.ToInt16(msgsize, 0);
290             int dataleft = size;
291             byte[] msg = new byte[size];
292             while (dataleft > 0)
293             {
294                 //接收数据
295                 recv = s.Receive(msg, offset, dataleft, 0);
296                 if (recv == 0)
297                 {
298                     break;
299                 }
300                 offset += recv;
301                 dataleft -= recv;
302             }
303             return msg;
304         }
305     }
306 }

这里还没有实现客户端在线修改kp ki kd参数的功能,pid计算用的参数是初始给定的定值。

 

接收消息Receive部分的代码,是不断的接收对方发送来的消息,不能分辨其发送的是kp ki参数的设定值(double型),还是速度设定值setSpeed(int或double型),还是欢迎消息welcome to the server(string型),所以,应该需要标记符,放在要发送的消息中,如:字节数组第一位是0,表示发送的是速度设定值,第一位为2表示kp参数设定值……

 

posted @ 2017-04-11 10:56  念苏苏0504  阅读(350)  评论(0编辑  收藏  举报