• socket编程的c#简单实现


    其实只要用到Socket联接,基本上就得使用Thread,是交叉使用的。
    C#封装的Socket用法基本上不算很复杂,只是不知道托管之后的Socket有没有其他性能或者安全上的问题。
    在C#里面能找到的最底层的操作也就是socket了,概念不做解释。
    程序模型如下:
    WinForm程序 : 启动端口侦听;监视Socket联接情况;定期关闭不活动的联接;
    Listener:处理Socket的Accept函数,侦听新链接,建立新Thread来处理这些联接(Connection)。
    Connection:处理具体的每一个联接的会话。

    1:WinForm如何启动一个新的线程来启动Listener:
     
         
    因为侦听联接是一个循环等待的函数,所以不可能在WinForm的线程里面直接执行,不然Winform也就是无法继续任何操作了,所以才指定一个新的线程来执行这个函数,启动侦听循环。
    这一个新的线程是比较简单的,基本上没有启动的参数,直接指定处理函数就可以了。
    2:Listener如何启动循环侦听,并且启动新的带有参数的线程来处理Socket联接会话。
    先看如何建立侦听:(StartListening函数)

    IPEndPoint localEndPoint = new IPEndPoint(_ipAddress, _port);
    // Create a TCP/IP socket. 
    Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    // Bind the socket to the local endpoint and  listen for incoming connections. 
    try
    {
           listener.Bind(localEndPoint);
           listener.Listen(
    20);//20 trucks

           
    // Start listening for connections. 
           while (true)
           
    {
                 
    // here will be suspended while waiting for a new connection. 
                 Socket connection = listener.Accept();
                 Logger.Log(
    "Connect", connection.RemoteEndPoint.ToString());//log it, new connection
                 ……
           }

    }
    ……


    基本步骤比较简单:
    建立本机的IPEndPoint对象,表示以本机为服务器,在指定端口侦听;
    然后绑定到一个侦听Socket上;
    进入while循环,等待新的联接;
    如果有新的联接,那么建立新的socket来对应这个联接的会话。
       值得注意的就是这一句联接代码:listener.Accept()。执行这一句的时候,程序就在这个地方等待,直到有新的联检请求的时候程序才会执行下一句。这是同步执行,当然也可以异步执行。
     
       新的联接Socket建立了(Accept之后),对于这些新的socket该怎么办呢?他们依然是一个循环等待,所以依然需要建立新的Thread给这些Socket去处理会话(接收/发送消息),而这个Thread就要接收参数了。
       Thread本身是不能接收参数的,为了让它可以接收参数,可以采用定义新类,添加参数作为属性的方法来解决。
       因为每一个Socket是一个Connection周期,所以我定义了这么一个类public class Connection。这个类至少有这样一个构造函数public Connection(Socket socket); 之所以这么做,就是为了把Socket参数传给这个Connection对象,然后好让Listener启动这个Thread的时候,Thread可以知道他正在处理哪一个Socket。
        具体处理的方法:(在Listener的StartListening函数,ocket connection = listener.Accept();之后)
        Connection gpsCn = new Connection(connection);
                        //each socket will be wait for data. keep the connection.
                        Thread thread = new Thread(new ThreadStart(gpsCn.WaitForSendData));
                        thread.Name = connection.RemoteEndPoint.ToString();
                        thread.Start();
     如此一来,这个新的socket在Accept之后就在新的Thread中运行了。
       3:Connection的会话处理
       建立了新的Connection(也就是socket),远程就可以和这个socket进行会话了,无非就是send和receive。
       现在先看看怎么写的这个线程运行的Connection. WaitForSendData函数

        while (true)
                
    {
                    bytes 
    = new byte[1024];
                    
    string data = "";
                    
    //systm will be waiting the msg of receive envet. like Accept();
                    
    //here will be suspended while waiting for socket income msg. 
                    int bytesRec = this._connection.Receive(bytes);
                    _lastConnectTime 
    = DateTime.Now;
                    
    if (bytesRec == 0)//close envent
                    {
                        Logger.Log(
    "Close Connection", _connection.RemoteEndPoint.ToString());
                        
    break;
                    }

                    data 
    += Encoding.ASCII.GetString(bytes, 0, bytesRec);
                    
    //…….handle your data.
                 }

    可以看到这个处理的基本步骤如下:
       执行Receive函数,接收远程socket发送的信息;
       把信息从字节转换到string;
       处理该信息,然后进入下一个循环,继续等待socket发送新的信息。
    值得注意的有几个:
       1:Receive函数。这个函数和Listener的Accept函数类似。在这个地方等待执行,如果没有新的消息,这个函数就不会执行下一句,一直等待。
       2:接收的是字节流,需要转化成字符串
       3:判断远程关闭联接的方式
       4:如果对方的消息非常大,还得循环接收这个data。
    4:如何管理这些联接(thread)
    通过上边的程序,基本上可以建立一个侦听,并且处理联接会话。但是如何管理这些thread呢?不然大量产生thread可是一个灾难。
    管理的方法比较简单,在Listener里面我定义了一个静态的哈希表(static public Hashtable Connections=new Hashtable();),存储Connection实例和它对应的Thread实例。而connection中也加入了一个最后联接时间的定义(private DateTime _lastConnectTime;)。在新链接建立的时候(Listener的Accept()之后)就把Connection实例和Thread实例存到哈希表中;在Connection的Receive的时候修改最后联接时间。这样我们就可以知道该Connection在哪里,并且会话是否活跃。
    然后在Winform程序里头可以管理这些会话了,设置设置超时。

  • 相关阅读:
    图文并茂记录下重新配置Win10系统Flutter环境--内含Android Studio 下载安装教程
    图文并茂解决Client does not support authentication protocol requested by server; consider upgrading MySQL
    图文并茂基于阿里云linux服务器部署nodejs项目并添加pm2守护nodejs项目运行进程(Linux version 4.19.81-17.1.al7.x86_64)
    超简单的图文并茂Linux上使用yum安装Mysql(Aliyun Linux release 2.1903 LTS)
    使用linux命令直接在网上下载文件,解压,改名
    解决使用linux部署nodejs服务测试代码返回中文是乱码
    Echarts点击多组数据多个柱子中的一个柱子,获取当前点击的是第几组数据,并获取点击的是当前组别第几根柱子,以及对应横坐标,
    flutter 2.X报错 Bad state: Insecure HTTP is not allowed by platform:
    flutter 2.x运行flutter run 报错Cannot run with sound null safety, because the following dependenciesdon'
    flutter 1.升级2.X在模型类中序列化JSON报错Non-nullable instance field 'title' must be initialized.
  • 原文地址:https://www.cnblogs.com/sleeper520/p/1320458.html
Copyright © 2020-2023  润新知