zoukankan      html  css  js  c++  java
  • Socket通信

    用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传送数据时,有时会发生数据粘包或数据丢失的情况,因此加入了很多的空循环起延时作用,从而可以将每次发送数据之间有时间间隔,从而互不影响,不会再粘包,但是这样会使程序运行效率变低,速度过慢,这样再复杂一些的算法,根本不能做到实时控制,实时传送,实时监控。因此这一点还要想其他的办法解决。

  • 相关阅读:
    20170421 F110 常见问题
    BAPI_ACC_DOCUMENT_POST 解决原因代码输入问题-利用BADI
    ABAP f4帮助输入多个值
    002 MIRO发票校验采购订单项目科目分配类别检查增强-20150819
    001infor record 计划时间取值增强-20150622
    003 F-47创建预付定金请求检查增强-20150819.docx
    整理开源协议问题 GPL APACHE
    拆我的跨界手环
    ThinkPHP 的一个神秘版本 ThinkPHP 1.2
    关于 Vue 方法前面的美元符号
  • 原文地址:https://www.cnblogs.com/1987-05-04/p/6644305.html
Copyright © 2011-2022 走看看