• c#网络编程使用tcpListener和tcpClient


    引自:http://ilewen.com/questions/514

    在本教程中,我会向你展示如何用C#建立一个线程中的TCP服务端。如果你用过windows的sockets编写程序,你就知道有多麻烦。感谢.net框架,使得网络编程变得更容易了。

    我们将建立一个非常简单的的服务器接受客户端连接,并可以发送和接收数据。服务器为每一个连接客户端产生一个线程,从理论上讲,可以接受多个连接(虽在实践中,Windows对此是有限制)。
    下面看代码:

    using System;
    using System.Text;
    using System.Net.Sockets;
    using System.Threading;
    using System.Net;
    
    namespace TCPServerTutorial
    {
        class Server
        {
            private TcpListener tcpListener;
            private Thread listenThread;
    
            public Server()
            {
                 this.tcpListener = new TcpListener(IPAddress.Any, 3000);
                 this.listenThread = new Thread(new ThreadStart(ListenForClients));
                 this.listenThread.Start();
            }
        }
    }

    上面建立了一个基本的服务器类。我们定义了一个TcpListener变量(TcpListener封装了底层套接字通信工作),同时定义了一个线程用于监听客户端的连接。接下来我们定义了ThreadStart的委托函数:ListenForClients。
    代码如下:

    private void ListenForClients()
    {
        this.tcpListener.Start();
    
        while (true)
        {
            //blocks until a client has connected to the server
            TcpClient client = this.tcpListener.AcceptTcpClient();
    
            //create a thread to handle communication
            //with connected client
            Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
            clientThread.Start(client);
        }
    }

    这个函数非常简单。首先,它启动TcpListener,然后循环接受连接。 AcceptTcpClient的调用将阻塞线程的执行,直到一个客户端连接,在这里,我们触发一个线程来处理与我们的新客户端的通信。我用了ParameterizedThreadStart委托,所以我可以传递AcceptTcpClient调用返回的TcpClient对象到新线程。

    ParameterizedThreadStart使用函数HandleClientComm。这个函数负责从客户端读取数据。让我们看看它。

    private void HandleClientComm(object client)
    {
        TcpClient tcpClient = (TcpClient)client;
        NetworkStream clientStream = tcpClient.GetStream();
    
        byte[] message = new byte[4096];
        int bytesRead;
    
        while (true)
        {
            bytesRead = 0;
    
            try
            {
                //blocks until a client sends a message
                bytesRead = clientStream.Read(message, 0, 4096);
            }
            catch
            {
                //a socket error has occured
                break;
            }
    
            if (bytesRead == 0)
            {
                //the client has disconnected from the server
                break;
            }
    
            //message has successfully been received
            ASCIIEncoding encoder = new ASCIIEncoding();
            System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
        }
    
        tcpClient.Close();
    }

    第一步将client类型转换为TcpClient类型,因为ParameterizedThreadStart委托只能接受基本对象类型。下一步,从TcpClient得到NetworkStream用来读取数据。之后,通过一个while循环从客户端读取数据。 read调用会一直处于阻塞状态,直到从客户端接收到数据。如果从客户端读取到零字节,那么说明客户端已断开。在该例子里,我只是一个字符串转换成字节数组,并将它输出到控制台。当然,你会做一些更复杂的工作。如果socket出现错误或客户端断开连接,你应该调用TcpClient对象的close函数关闭连接,释放它使用的任何资源。

    上面就是创建一个服务器线程,接受连接,并从客户端读取数据所需做的所有的事情。当然,如果服务端不能发送数据,那么就没什么用了。下面,让我们看看如何将数据发送到我们的连接的一个客户端。

    NetworkStream clientStream = tcpClient.GetStream();
    ASCIIEncoding encoder = new ASCIIEncoding();
    byte[] buffer = encoder.GetBytes("Hello Client!");
    
    clientStream.Write(buffer, 0 , buffer.Length);
    clientStream.Flush();

    从AcceptTcpClient返回的TcpClient对象用来发送数据给客户端。因此需要在服务端保存这些对象。通常可以创建一个TcpClient对象的集合。发送数据是非常简单的,只需要得到client的NetworkStream对象,然后调用它的write方法就可以了。

    TCP服务端已经完成了。比较难的部分是定义一个协议用来在客户端和服务端之间发送信息。应用层的协议通常对不同的应用都是不一样的。所以我不打算讲解更多,你只需要实现你自己的。

    如果没有一个客户端连接到服务端,那么这个服务端还有存在的意思吗?本教程主要是讲服务端编程,但这里有一个简短的代码,说明了如何设置一个基本的TCP连接,并发送一段数据。

    TcpClient client = new TcpClient();
    
    IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
    
    client.Connect(serverEndPoint);
    
    NetworkStream clientStream = client.GetStream();
    
    ASCIIEncoding encoder = new ASCIIEncoding();
    byte[] buffer = encoder.GetBytes("Hello Server!");
    
    clientStream.Write(buffer, 0 , buffer.Length);
    clientStream.Flush();

    第一步工作是获取客户端到服务端的连接。使用TcpClient.Connect方法。它需要知道服务端的IPEndPoint,在这里,我将连接到本地主机,端口号3000。然后发送字符串"hello Server!"

    注意:从客户端或服务器写并不总是等于一个在接收端读。例如,客户端向服务器发送10个字节,但服务器可能无法在第一次读取的时候得到所有10个字节。使用TCP,几乎保证最终得到所有10个字节,但它可能需要不止读取一次。所以当设计交互协议的时候要注意这一点。

  • 相关阅读:
    HDU5418.Victor and World(状压DP)
    POJ2686 Traveling by Stagecoach(状压DP)
    POJ3254Corn Fields(状压DP)
    HDU5407.CRB and Candies(数论)
    CodeForces 352D. Jeff and Furik
    CodeForces 352C. Jeff and Rounding(贪心)
    LightOj 1282 Leading and Trailing
    Ural 1057. Amount of Degrees(数位DP)
    HDU 2089 不要62 (数位DP)
    HDU5366 The mook jong (DP)
  • 原文地址:https://www.cnblogs.com/nearpengju123/p/4725641.html
Copyright © 2020-2023  润新知