將以前的通訊代碼,以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計算用的參數是初始給定的定值。spa

 

接收消息Receive部分的代碼,是不斷的接收對方發送來的消息,不能分辨其發送的是kp ki參數的設定值(double型),仍是速度設定值setSpeed(int或double型),仍是歡迎消息welcome to the server(string型),因此,應該須要標記符,放在要發送的消息中,如:字節數組第一位是0,表示發送的是速度設定值,第一位爲2表示kp參數設定值……線程

相關文章
相關標籤/搜索