标签:退出 any data pad increase esc bind 执行 显示
用Socket通信实现本地计算机与云服务器的连接,云服务器端有一个简单的增量式PID算法的计算代码。本地依次输入速度设定值并通过Socket通信传送到服务器端,服务器端将PID计算得到的实际速度值存放在一个集合中,然后再次建立新的套接字,与另一个客户端建立通信连接,实现将PID计算得到的实际速度值传送到新的客户端中。
客户端-1代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
namespace _3_4客户端_PID
{
public class Program
{
static void Main(string[] args)
{
byte[] data = new byte[1024];
string strInput;
string stringData;
//创建服务器端IPEndPoint对象
IPEndPoint Ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 125);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
server.Connect(Ipep);//Connect 建立与远程主机的连接
}
catch (Exception e)
{
Console.WriteLine("无法连接到服务器");
Console.WriteLine(e.ToString());
return;
}
finally
{ }
//接收数据
int receive = server.Receive(data);//receive是接收到的数据的长度 所以是int型 接收到的信息,存在data这个byte字节数组中
stringData = Encoding.ASCII.GetString(data, 0, receive);
Console.WriteLine(stringData);//将从服务器接收到的数据打印出来
while (true)
{
Console.WriteLine("请输入速度设定值,输入esc断开与服务器的连接,程序退出");
strInput = Console.ReadLine();
if (strInput == "esc")
{
break;//break,跳出循环,所以不会执行后边的send语句,本次发送到服务器端的数据长度为0
}
//发送数据
try
{
double douInput = Convert.ToDouble(strInput);
server.Send(Encoding.ASCII.GetBytes(strInput));
}
catch
{
Console.WriteLine("输入的设定速度格式不正确,请重新输入");
Console.ReadKey();
}
}
//释放资源
Console.WriteLine("断开与服务器的连接");
server.Shutdown(SocketShutdown.Both);
server.Close();
Console.ReadKey();
}
}
}
服务器端代码:
注意,127.0.0.1是本机循环地址 若想建立与非本机计算机的通信连接,要把IP地址改写为服务器端所在计算机的ip地址 云服务器就写公网IP即可。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Threading;
using System.Diagnostics;
namespace _3_3_服务器端_PID
{
public static class actualSpeed
{
public static ArrayList list = new ArrayList();//集合存储PID控制器计算后的输出值
public static double number;
}
public class Program
{
static void Main(string[] args)
{
double[] nums = new double[3];//存储3个偏差值e(k) e(k-1) e(k-2)
double actual = 0;
double set = 0;
//int receive;//接收到的数据长度
//定义一个空字节数组date作为数据缓冲区,用于缓冲流入和流出的信息
byte[] date = new byte[1024];
//为本服务器定义IPEndPoint对象
IPEndPoint Ipep = new IPEndPoint(IPAddress.Any, 125);//指定地址和端口号
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(Ipep);
newsock.Listen(10);//置于监听状态
Console.WriteLine("waiting for a message from client");
//接收来自客户端的接入尝试连接,并返回连接客户端的ip地址
Socket client = newsock.Accept();
IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
//返回客户端的ip地址和端口号
Console.WriteLine("connected with {0} at port {1}", clientep.Address, clientep.Port);
//发送欢迎消息到客户端,等待客户端消息
string welcome = "welcome to the server";
date = Encoding.ASCII.GetBytes(welcome);//以字节数组的形式 将欢迎信息发送给客户端
client.Send(date, date.Length, SocketFlags.None);
// Send/Receive() 进行数据传送 Send发送数据
int i = 1;//作为下标,给静态数组actualSpeed依次赋值
while (true)
{
//定义缓冲区
date = new byte[1024];
int recei = client.Receive(date);//Receive接收数据 返回接收数据的长度 所以为int类型
//如果接收到的数据长度是0,则自动退出本次while循环
if (recei == 0)
{
break;
}
string strSet = Encoding.ASCII.GetString(date, 0, recei);
set = double.Parse(strSet);
nums[0] = set - actual;
double increase = 0.4 * (nums[0] - nums[1]) + 0.53 * nums[0] + 0.1 * (nums[0] - 2 * nums[1] + nums[2]);
actual += increase;
actualSpeed.list.Add(actual);//将每次的实际速度值 添加到集合中
Console.WriteLine(actualSpeed.list[i - 1]);//输出实际的速度值 成功!
i++;
Console.WriteLine("设定速度为{0},增长的速度为{1},实际速度为{2}", set, increase, actual);
nums[1] = nums[0];
nums[2] = nums[1];
}//while循环结束括号
Console.WriteLine("无法与 {0} 连接", clientep.Address);
//释放资源
client.Close();
newsock.Close();
Console.ReadKey();
//***
//***将得到的实际速度(list集合),再用一次Socket通信,发送给3-5项目接收 成功!
//***
IPEndPoint IPep2 = new IPEndPoint(IPAddress.Any, 127);
Socket newsock2 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newsock2.Bind(IPep2);
newsock2.Listen(10);
Console.WriteLine("等待3-5项目客户端的连接");
Socket client2 = newsock2.Accept();//等待客户端的连接
IPEndPoint clientep2 = (IPEndPoint)client2.RemoteEndPoint;
Console.WriteLine("与{0}连接在{1}端口", clientep2.Address, clientep2.Port);
string welcome2 = "welcome to the second server";
//Thread.Sleep(1000);//延时作用 是线程休息等待1S
Stopwatch sw = new Stopwatch();//记录程序的执行时间
sw.Start();
for (int i2 = 0; i2 < 30000; i2++)
{
for (int j2 = 0; j2 < 20000; j2++)
{
//空循环
}
}
sw.Stop();
TimeSpan ts = sw.Elapsed;
Console.WriteLine(ts.TotalSeconds);
date = new byte[1024];
date = Encoding.ASCII.GetBytes(welcome2);//字符串转换为字节数组 传送给客户端
client2.Send(date, date.Length, SocketFlags.None);//send发送给客户端
//发送实际速度集合的长度 给3-5客户端 成功!
for (int i3 = 0; i3 < 10000; i3++)
{
for (int j3 = 0; j3 < 10000; j3++)
{
}
//空循环 起延迟作用
}
date = new byte[1024];
date = Encoding.ASCII.GetBytes(actualSpeed.list.Count.ToString());
client2.Send(date, date.Length, SocketFlags.None);
//将每一次的实际速度先转换为string 再转换为字节发送给客户端 用for循环依次传递 成功!
//如果是直接将char数组转换为字节 再发送给客户端 发生乱码情况 ?不明白其中错误原因?
double[] values = actualSpeed.list.ToArray().Select(o => Convert.ToDouble(o)).ToArray();
string[] strvalue = new string[values.Length];
for (int j = 0; j < values.Length; j++)
{
strvalue[j] = values[j].ToString();//将实际速度集合转换为string数组
for (int i4 = 0; i4 < 10000; i4++)
{
for (int j4 = 0; j4 <10000; j4++)
{
}
//空循环 起延迟作用
}
date = new byte[1024];
date = Encoding.ASCII.GetBytes(strvalue[j]);//string数组中的每个元素一次转换为字节 发送给客户端
client2.Send(date, date.Length, SocketFlags.None);
}
//////传送单个数据 最后一个实际速度值
////date = Encoding.ASCII.GetBytes(actual.ToString());//传送最后一个单个数据 成功!
////client2.Send(date, date.Length, SocketFlags.None);
////client.Send(s, s.Length, SocketFlags.None);
Console.WriteLine("传送数据成功!");
client2.Close();
newsock2.Close();
Console.ReadKey();
}//Main函数
}//类 program
}//命名空间
客户端-2代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Collections; namespace _3_5_接收服务器端传回的数据 { class Program { static void Main(string[] args) { ArrayList list = new ArrayList(); byte[] data = new byte[1024]; IPEndPoint IPep2=new IPEndPoint(IPAddress.Parse("127.0.0.1"),127); Socket server2 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { server2.Connect(IPep2); for (int i1 = 0; i1 < 10000; i1++) { for (int j1 = 0; j1 < 10000; j1++) { } //空循环 起延迟作用 } } catch (SocketException e) { Console.WriteLine("连接服务器失败"); Console.WriteLine(e.ToString()); Console.ReadKey(); return; } finally { } //接收来自服务器的数据 for (int i2 = 0; i2 < 10000; i2++) { for (int j2 = 0; j2 < 10000; j2++) { } //空循环 起延迟作用 } int receive = server2.Receive(data); string stringData = Encoding.ASCII.GetString(data, 0, receive); Console.WriteLine(stringData);//welcome to the second server ////接收并显示最后一个实际速度 成功! //int rece = server2.Receive(data); //string datavs = Encoding.ASCII.GetString(data, 0, rece);//传送单个数据 即最后一次的实际速度 成功! //Console.WriteLine(datavs); //接收实际速度数组的长度 count 成功! for (int i3 = 0; i3 < 10000; i3++) { for (int j3 = 0; j3 < 10000; j3++) { } //空循环 起延迟作用 } data = new byte[1024]; int rece = server2.Receive(data); string length = Encoding.ASCII.GetString(data, 0, rece);// 成功! Console.WriteLine(length); int n=Convert.ToInt32(length); //依次接收来自服务器端传送的实际速度值 成功! string[] speed = new string[n]; for (int i = 0; i <n ; i++) { for (int i4 = 0; i4 < 10000; i4++) { for (int j4 = 0; j4 < 10000; j4++) { } //空循环 起延迟作用 } data = new byte[1024]; int rece2 = server2.Receive(data); speed[i]=Encoding.ASCII.GetString(data,0,rece2); Console.WriteLine("第{0}次的实际速度是{1}", i+1, speed[i]); } Console.ReadKey(); } } }
这样实现了服务器计算得出的速度值,给新的客户端。但是存在一个问题,就是在与客户端-2传送数据时,有时会发生数据粘包或数据丢失的情况,因此加入了很多的空循环起延时作用,从而可以将每次发送数据之间有时间间隔,从而互不影响,不会再粘包,但是这样会使程序运行效率变低,速度过慢,这样再复杂一些的算法,根本不能做到实时控制,实时传送,实时监控。因此这一点还要想其他的办法解决。
标签:退出 any data pad increase esc bind 执行 显示
原文地址:http://www.cnblogs.com/1987-05-04/p/6644305.html