码迷,mamicode.com
首页 > Windows程序 > 详细

c#网络编程使用tcpListener和tcpClient

时间:2015-08-12 23:18:23      阅读:439      评论:0      收藏:0      [点我收藏+]

标签:

引自: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个字节,但它可能需要不止读取一次。所以当设计交互协议的时候要注意这一点。

c#网络编程使用tcpListener和tcpClient

标签:

原文地址:http://www.cnblogs.com/nearpengju123/p/4725641.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!