【光学相机】关于网络通信的方法及函数_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 【光学相机】关于网络通信的方法及函数

【光学相机】关于网络通信的方法及函数

 2017/12/7 11:36:07  Yulong5759  程序员俱乐部  我要评论(0)
  • 摘要:一.TcpClient与TcpServe。首先我们需要知道服务器的IP地址,在服务器端建立监听,当监听到客户端的连接请求后,连接到客户端。而客户端则需要连接到指定的IP服务器地址,建立网络流,则可以实现通信。接下来给出一个服务器端与客户端的实例:服务器端:usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Net
  • 标签:方法 函数 网络

一.TcpClient与TcpServe。

首先我们需要知道服务器的IP地址,在服务器端建立监听,当监听到客户端的连接请求后,连接到客户端。

而客户端则需要连接到指定的IP服务器地址,建立网络流,则可以实现通信。

接下来给出一个服务器端与客户端的实例:

服务器端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;

namespace fuwuqi
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                IPAddress Ip = IPAddress.Parse("127.0.0.1");
                //IPAddress提供网际协议地址的类,Parse将IP地址字符串转换为IPAddress的实例   
                TcpListener TcpList = new TcpListener(Ip, 8888);
                //TcpListener网络侦听类,从TCP网络客户端侦听连接,TcpListener (参数1,参数2),参数1表示本地IP地址,参数2表示用来侦听传入的端口连接   
                TcpList.Start();
                //启动对挂起连接数的传入链接请求的侦听   
                Console.WriteLine("Server start!");
                Console.WriteLine("Ip address:" +TcpList.LocalEndpoint);
                //LocalEndpoint获取服务端(即本地)地址与端口等信息   
                Console.WriteLine("Wait");
                Socket Soc = TcpList.AcceptSocket();//相当于启动客户端后,Socket被挂起
                //AcceptSocket表示接受挂起的连接请求,Socket为套接字接口的类   
                Console.WriteLine("Received Connection:" + Soc.RemoteEndPoint);
                //RemoteEndPoint获取客户端地址与端口等信息   
                byte[] b = new byte[100];
                int k = Soc.Receive(b);
                //Soc.Receive(b)从socket接收数据,将数据存入接收缓冲区列表中,k的值为该数据的长度   
                Console.WriteLine("Received data from client:");
                for (int i = 0; i < k; i++)
                    Console.Write(Convert.ToChar(b[i]));
                //Convert.ToChar(b[i])将数组b转换基本数据类型为char的类型并输出   
                ASCIIEncoding AS = new ASCIIEncoding();
                //ASCIIEncoding表示Unicode字符的ASCII字符编码
                Soc.Send(AS.GetBytes("Received data!"));
                //Soc.Send向客户端发送数据,AS.GetBytes()获得括号中字符串的bytes值   
                Soc.Close();
                //关闭连接并释放所有关联的资源   
                TcpList.Stop();
                //关闭侦听   
                Console.ReadLine();
                //等待输入,起到暂停的作用   
            }
            catch (Exception e)
            {
                Console.WriteLine("Error!" + e.StackTrace);
                //获取当前异常发生时调用堆栈上的帧的字符串   
            }
        }
    }
}

此时服务器端应用的是Socket类发送数据流,Socket类用于客户端和服务器都可,其发送机制是以一种包的形式发送,在做项目时,发现Socket接收到的数据包与发送到的数据包长度不一定吻合,有阻塞,所以使用Socket数据包发送时,接收和发送的数据组要指定长度,太长也会丢数。

客户端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Sockets;
namespace kehuduan
{
    class Program
    {
        
            static void Main(string[] args)  
        {
                try
                {
                    TcpClient TcpClient = new TcpClient();
                    //TcpClient为TCP网络服务提供客户端连接的类   
                    TcpClient.Connect("127.0.0.1", 8888);
                    //Connect方法使用指定的IP地址和端口号将客户端连接到远程TCP主机   
                    Console.WriteLine("Connect Complete");

                    Console.WriteLine("Input string:");
                    String str = Console.ReadLine();
                    //定义字符串str变量,保存输入的字符   
                    Stream stm = TcpClient.GetStream();
                    //定义数据流,用于发送和接收数据   
                    ASCIIEncoding AS = new ASCIIEncoding();
                    byte[] b = AS.GetBytes(str);
                    //将字符串转换为byte类型   
                    stm.Write(b, 0, b.Length);
                    //Write(参数1,参数2,参数3)表示向服务端发送字符串,参数1指将此数组复制到当前流,参数2指从零开始的字节偏移量,参数3指要写入当前流的字节数(即字符串长度)   
                    Console.WriteLine("Send Complete");
                    byte[] bb = new byte[100];
                    int k = stm.Read(bb, 0, 100);
                    //stm.Read在当前流中读入服务端发来的响应信息,其参数与Write方法参数一致,k值为读入字符串的长度   
                    for (int i = 0; i < k; i++)
                        Console.Write(Convert.ToChar(bb[i]));
                    TcpClient.Close();
                    //释放TcpClient实例,并不关闭基础连接   
                    Console.ReadLine();
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error!" + e.StackTrace);
                }
            }
        }
    }

上面展示了客户端与服务器端的简单通信。作为例子程序学习,接下来对自己做的项目中连接摄像头服务器做一个记录。

首先,把摄像头作为服务器端,定义客户端:

   TcpClient client = new TcpClient("IP",8080);

获取网络流:

  NetworkStream networkstream = client.GetStream();//获取网络流

此时可以建立与服务器端的网络流连接,如果需要从网络流中读取数据或者写入数据,使用了BinaryReader/BinaryWriter或者StreamReader/StreamWriter,实例化后,就可实现对流的读写

BinaryReaderbr = new BinaryReader(networkstream);
BinaryWriter bw = new BinaryWriter(networkstream);
我对这两个的理解是StreamReder读取函数ReadToEnd,ReadLine等,读取出来是字符串类型。而BinaryReader可以按字节读取。根据需求选取。

(笔记StreamReader的方法: sr.BaseStream.Seek(0, SeekOrigin.Begin);//从流中当前开始的位置(SeekOrigin.begin)偏移0位读取)

如果需要对服务器发送数据直接写入流,使用Write等函数就可以了。

 

这里对自己找的资料也做一个总结。

MemoryStream类:

Memmory类相当于一个缓存流,首先需要对这个流开辟一个空间,然后将数据放入流中对其进行操作。该流的优势在于可以将数据先放入流中,然后使用指针对流中的任一个字节进行操作。

学习例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //属性测试
            MemoryStream ms = new MemoryStream();
            Console.WriteLine(ms.CanRead);      //True  内存流可读
            Console.WriteLine(ms.CanSeek);      //True  内存流支持查找,指针移来移去的查找
            Console.WriteLine(ms.CanTimeout);   //False 内存流不支持超时
            Console.WriteLine(ms.CanWrite);     //True  内存流可写

            Console.WriteLine(ms.Capacity);     //0     分配给该流的字节数
            byte[] bytes = Encoding.UTF8.GetBytes("abcdedcba");//字符转为ASCII
            ms.Write(bytes, 0, bytes.Length);   //已将一段文本写入内存
            int l = bytes.Length;
            Console.WriteLine(ms.Capacity);     //256   再次读取为文本流分配的字节数已经变成了256,看来内存流是根据需要的多少来分配的
            Console.WriteLine(ms.Length);       //9    这个是流长度,通常与英文的字符数一样,真正占用的字节数。

            Console.WriteLine(ms.Position);     //9    流当前的位置,该属性可读可设置

            //Console.WriteLine(ms.ReadTimeout);    由于流不支持超时,此属性如果读取或者设置的话会报错
            //Console.WriteLine(ms.WriteTimeout);   由于流不支持超时,此属性如果读取或者设置的话会报错

            //方法测试
            
            byte[] byte1 = ms.GetBuffer();          //返回无符号字节数组 差点被忽悠了,无符号字节数组 其实就是byte(0~255),有符号字节sbyte(-128~127)
            string str1 = Encoding.UTF8.GetString(byte1);
            Console.WriteLine(str1);    //输出    abcdedcba
            long p = ms.Position;//指针当前位置
            ms.Position = 0;
            ms.Seek(0, SeekOrigin.Current);    //设置当前流正在读取的位置 为开始位置即从0开始
            //从内存中读取一个字节
            int i = ms.ReadByte();
            Console.WriteLine(i);                   //输出99
            byte[] bytes3 = ms.ToArray();
            foreach (byte b in bytes3)
            {
                Console.Write(b + "-");//用于对比   输出 97-98-99-100-101-100-99-98-97-   可以看到    0,1,2第二位刚好是99
            }

            MemoryStream ms2 = new MemoryStream();
            byte[] bytes6 = Encoding.UTF8.GetBytes("abcde");
            ms2.Write(bytes6, 0, bytes6.Length);
            Console.WriteLine(ms2.Position);    //输出5 写完之后流的位置就到了最后,因此想用read读取必须加下面这一行代码。 

            //ms2.Seek(0, SeekOrigin.Begin);    //想要用Read方法读取完整的流,必须设置当前位置,Read是从Position的位置开始读。
            ms2.Position = 0;                   //Read是从当前位置开始读,这行代码和上面一行意义一样。
            byte[] byteArray = new byte[5] { 0, 0,0, 0, 0 }; //数组附初值全部是0
            ms2.Read(byteArray, 2, 1);   //读取一个字节,byteArray的第一个元素中,(注意从0开始)读取数据流里第二个位子开始读取一个
            Console.WriteLine(Encoding.UTF8.GetString(byteArray)); //nnann
            ms2.Read(byteArray, 2, 2);
            Console.WriteLine(Encoding.UTF8.GetString(byteArray)); //nnabn    //当超出接收数组总长度的时候,后面的元素会被移开


            //设置当前流的长度
            Console.WriteLine(ms.Length);   //输出9   当前流的长度是9
            ms.SetLength(20);
            Console.WriteLine(ms.Length);   //输出20
            foreach (byte b in ms.ToArray())    //将流的内容也就是内存中的内容转换字节数组
            {
                Console.Write(b + "-");     //输出 97-98-99-100-101-100-99-98-97-0-0-0-0-0-0-0-0-0 由于设置了长度,因此空的自动补0
            }
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));   //输出    abcdedcba   虽然长度变长了,但是没影响读取数据

            MemoryStream ms1 = new MemoryStream();
            byte[] bytes4 = ms1.ToArray();
            Console.WriteLine("此内存流并没有写入数据(Write)" + Encoding.UTF8.GetString(bytes4));//输出    此内存流并没有写入数据(Write)  因为内存为空


            //下面来一个指定位置的写入
            MemoryStream ms3 = new MemoryStream();
            byte[] bytesArr = Encoding.ASCII.GetBytes("abcdefg");
            ms3.Write(bytesArr, 0, bytesArr.Length);
            ms3.Position = 2;
            ms3.WriteByte(97);  //97代表的是a   这段代码的意思是,将原先第二个的c替换为a
            string str = Encoding.ASCII.GetString(ms3.ToArray());
            Console.WriteLine(str); //输出 abacdefg

            byte[] byteArr1 = Encoding.ASCII.GetBytes("kk");
            ms3.Position = 4;
            ms3.Write(byteArr1, 0, byteArr1.Length);
            Console.WriteLine(Encoding.UTF8.GetString(ms3.ToArray()));  //abadkkg   //从第4位替换掉了两个字节为KK

            Console.ReadKey();
        }
    }
}

 

发表评论
用户名: 匿名