• 【.NET】网络编程总结


    1、首先说下计算机网络中的TCP/IP参考模型

      TCP/IP把网络分为5层,每一层负责完成不同的功能

        1)应用层:传输报文,提供各种网络应用,有FTP、SMTP、HTTP等协议

        2)运输层:传输报文段,为应用程序的客户机和服务器之间提供传输应用层报文服务,协议有TCP,UDP

        3)网络层:传输数据包,协议有IP协议,选路协议

        4)链路层:传输数据帧,以太网就属于这个层

        5)物理层:在节点之间传输比特流

      应用程序是通过套接字访问网络下层的服务的,套接字是网络运输层和应用层的一个编程接口,在程序中通过套接字来进行TCP和UDP传输,运输层以下的层对程序员透明

    TCP和UDP是最基本的传输协议,应用层的所有协议都是基于这两个协议进行封装扩展的

      TCP:可靠的,面向连接的连接数据传输服务,传输的是字节流,能保证数据的有序性

        1)建立连接(三次握手)  2)传输数据  3)断开连接(四次握手)

      UDP:不可靠,面向数据报的无连接的数据传输服务,传输的是是数据包,不保证数据的有序性

        广播:可以向同一个子网内的所有主机发送广播数据

        组播:可以向所有加入组网的主机发送组播数据

    2、编程(本节由于篇幅太长,这里只说TCP)

      .NET 框架提供了下面几个类对实现网络通信:

        Socket:提供最基本的TCP和UDP服务

        TcpListener/TcpClient 和 UdpClient:对Socket类进行了基本封装

        NetworkStream:网络流,对网络数据的写入和读取

      使用套接字的步骤

        TCP:服务器:创建套接字 -》 绑定套接字Bind -》 监听套接字Listen -》 接受连接Accept -》 发送/接受Send/Receive -》 关闭套接字CLose

          :客户端:创建套接字 -》                     连接 -》      发送/接受Send/Receive -》 关闭套接字CLose

        UDP:创建套接字 -》 绑定套接字Bind -》  发送/接受SendTo/ReceiveFrom -》 关闭套接字CLose

      1)Socket(使用异步方式连接和收发信息,因为等待连接和等待数据的时候会让主线程阻塞)

         这里就不贴代码了,跟下面的差不多,后面下载的代码有(我用的VS2012,低版本不能查看可以直接看源文件的代码)

      2)TcpListener/TcpClient(这里也使用异步方式来连接和接收信息)

        首先创建一个异步用的数据对象

            public class StateObject
            {
                public NetworkStream networkstream = null;
                public byte[] buffer = new byte[1024];
                public StateObject(NetworkStream netstream)
                {
                    this.networkstream = netstream;
                }
            }

        1)服务器端(异步监听,当收到连接,则异步读取数据,注意捕获连接断开时的异常)

            TcpListener listener;
            NetworkStream networkstream;
    
            private void btnBind_Click(object sender, EventArgs e)
            {
                //绑定,启动异步接受连接
                try
                {
                    int port = int.Parse(tbPort.Text);
                    IPAddress ipaddress = IPAddress.Parse(tbIP.Text);
                    IPEndPoint endpoint = new IPEndPoint(ipaddress, port);
                    
                    listener = new TcpListener(endpoint);
                    listener.Start(10);        //监听数位10
                    //开始异步接收连接请求
                    listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener);
                    btn.Text = "Close";
                }
                catch (ArgumentNullException) { }
                catch (SocketException) { }
            }
            //异步接收请求函数
            public void DoAcceptTcpClientCallback(IAsyncResult ar)
            {
                TcpListener listener = (TcpListener)ar.AsyncState;
                try
                {
                    TcpClient client = listener.EndAcceptTcpClient(ar);
                    //收到连接
                    this.BeginInvoke(new ThreadStart(() =>
                    {
                        //收到连接请求,这里可以让主线程更新UI
                    }));
                    networkstream = new NetworkStream(client.Client);
                    StateObject so = new StateObject(networkstream);
                    
                    //开始异步读取数据
                    networkstream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so);
    
                    //如果需要继续监听,则继续异步接收
                    listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener);
                }
                catch (ObjectDisposedException)
                {
                    //Socket关闭
                }
            }
            //异步读取数据函数
            public void ReadCallback(IAsyncResult ar)
            {
                StateObject so = (StateObject)ar.AsyncState;
                try
                {
                    NetworkStream myNetworkStream = so.networkstream;
                    int length = myNetworkStream.EndRead(ar);
                    string receivemsg = Encoding.UTF8.GetString(so.buffer, 0, length);
                    this.BeginInvoke(new ThreadStart(() =>
                    {
                        //收到数据,在这里可以让主线程更新UI
                    }));
                    so.buffer = new byte[1024];
                    //继续接收数据
                    myNetworkStream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so);
                }
                catch (IOException)
                {
                    this.BeginInvoke(new ThreadStart(() =>
                    {
                        //连接断开
                    }));
                    networkstream = null;
                }
            }

        这样,服务器端就完成了监听

      2)客户端(同样通过异步实现)

            TcpClient client;
            NetworkStream networkstream;
            private void btnConnect_Click(object sender, EventArgs e)
            {
                int port = int.Parse(tbPort.Text);
                IPAddress ipaddress = IPAddress.Parse(tbIP.Text);
                IPEndPoint endpoint = new IPEndPoint(ipaddress, port);
    
                if (client == null)
                {
                    //开始异步连接
                    client = new TcpClient();
                    client.BeginConnect(ipaddress, port, ConnectCallback, client);
                }
            }
            private void ConnectCallback(IAsyncResult ar)
            {
    
                TcpClient t = ar.AsyncState as TcpClient;
                try
                {
                    t.EndConnect(ar);
                    networkstream = t.GetStream();
                    this.BeginInvoke(new ThreadStart(() =>
                    {      
                        //连接成功                
                    }));
                    //开始异步接受数据
                    StateObject so = new StateObject(networkstream);
                    networkstream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so);
                }
                catch (SocketException)
                { 
                    this.BeginInvoke(new ThreadStart(() => 
                    {
                        //连接失败,让UI更新
                    }));
                }
            }
            public void ReadCallback(IAsyncResult ar)
            {
                StateObject so = (StateObject)ar.AsyncState;
                try
                {
                    NetworkStream myNetworkStream = so.networkstream;
                    int length = myNetworkStream.EndRead(ar);
                    string receivemsg = Encoding.UTF8.GetString(so.buffer, 0, length);
                    this.BeginInvoke(new ThreadStart(() =>
                    {
                        //更新UI
                    }));
                    //继续异步接受数据
                    so.buffer = new byte[1024];
                    myNetworkStream.BeginRead(so.buffer, 0, so.buffer.Length, ReadCallback, so);
                }
                catch (IOException)
                {
                    this.BeginInvoke(new ThreadStart(() =>
                    {
                        //连接断开
                    }));
                    networkstream = null;
                }
            }

      3)接下来是发送数据

            private void btnSend_Click(object sender, EventArgs e)
            {
                if (networkstream != null)
                {
                    byte[] sendbyte = System.Text.Encoding.UTF8.GetBytes("你好:)");
                    networkstream.Write(sendbyte, 0, sendbyte.Length);
                }
                else
                {
                    tbMsg.AppendText("未连接\n");
                }
            }

      具体项目代码  https://files.cnblogs.com/bomo/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B.zip

  • 相关阅读:
    细数阿里云在使用 Docker 过程中踩过的那些坑
    细数阿里云在使用 Docker 过程中踩过的那些坑
    javascript – 从页面停用浏览器打印选项(页眉,页脚,页边距)?
    jquery children()方法
    jquery 获取输入框的值
    java BigDecimal加减乘除
    window.print()打印时,如何自定义页眉/页脚、页边距
    深入分析:12C ASM Normal冗余中PDB文件块号与AU关系与恢复
    我不是药神,救不了你的穷根
    Install fail! Error: EPERM: operation not permitted
  • 原文地址:https://www.cnblogs.com/bomo/p/2867417.html
Copyright © 2020-2023  润新知