TCP编程

TcpClient类

    TcpClient类为TCP网络服务提供客户端连接,它构建于Socket类之上,以提供较高级别的TCP服务,即提供了通过网络连接、发送和接收数据的简单方法。用于在同步阻止模式下通过网络来连接、发送和接收流数据。另外,通过与NetworkStream对象的关联,使得用户可以通过流操作方式实现对网络连接状态下数据的发送和接收。

流程:

1.创建TcpClient实例

TcpClient类有4种构造函数的重载形式,分别对应4种创建实例的方法。

(1)TcpClient( ),这种不带任何参数的构造函数将使用本机默认的IP地址并将使用默认的通信端口号0。当然,如果本机不止一个IP地址时将无法选择使用。

(2)TcpClient(AddressFamily),使用指定的地址族初始化TcpClient类的新实例。

(3)TcpClient(IPEndPoint),即使用本机IPEndPoint创建TcpClient的实例。其中IPEndPoint将网络端点表示为IP地址和端口号,用于指定在建立远程主机连接时所使用的本地网络接口IP地址和端口号。

(4)TcpClient (String, Int32),初始化 TcpClient 类的新实例并连接到指定主机上的指定端口。

因此,在TcpClient的构造函数中,如果没有指定远程主机名和端口号,它只是用来实例化TcpClient,同时实现与本地IP地址和Port端口的绑定。

2.与远程主机建立连接

       如果在TcpClient的实例化过程中没有实现与远程主机的连接,则可以通过Connect方法来实现与指定远程主机的连接。Connect方法使用指定的主机名和端口号将客户端连接到远程主机,其使用方法如下。

(1)Connect(IPEndPoint),使用指定的远程网络终结点将客户端连接到远程TCP主机。

(2)Connect(IPAddress),使用指定的IP地址和端口号将客户端连接到远程TCP主机。

(3)Connect (IPAddress[],Int32),使用指定的IP地址和端口号将客户端连接到远程TCP主机。

(4)Connect(String, Int32),使用指定的主机名和端口号将客户端连接到指定主机上的指定端口。

如下代码段描述了TcpClient实例的创建以及与指定远程主机的连接过程。

m_client = new TcpClient( );

m_client.Connect(m_servername, m_port);

3.利用NetworkStream实例发送和接收数据

      TcpClient类创建在Socket之上,提供了更高层次的TCP服务抽象,特别是在网络数据的发送和接收方面,TcpClient使用标准的Stream流处理技术,通过使用NetworkStream实例的读写操作来实现网络数据的接收和发送,因此更加方便直观。但NetworkStream与普通流Stream有所不同,NetworkStream没有当前位置的概念,不支持查找和对数据流的随机访问。

该方法首先通过TcpClient.GetStream来返回NetworkStream实例,进而利用所获取的NetworkStream实例的读写方法Write和Read来发送和接收数据,其实现代码如下所示。

rs = new StreamReader(m_client.GetStream( ));//获取接收数据的网络流实例

ws = m_client.GetStream( ); //获取发送数据的网络流实例

m_returnData = rs.ReadLine( ); //接收网络数据

Console.WriteLine(m_returnData);

ws.Write(data, 0, data.Length); //向网络发送数据

4.关闭TCP套接字

 在与服务器完成通信后,应该调用Close( )方法释放所有的资源。

 m_client.Close( );

TcpListener类

   TcpClient类实现了客户端编程抽象,因此构建客户端网络应用程序便可以直接使用TcpClient取代Socket,更加方便易用。同样,对于服务器端应用程序的构建,C#提供了TcpListener类。该类也是构建于Socket之上,提供了更高抽象级别的TCP服务,使得程序员能更方便地编写服务器端应用程序。

    通常情况下,服务器端应用程序在启动时将首先绑定本地网络接口的IP地址和端口号,然后进入侦听客户请求的状态,以便于客户端应用程序提出显式请求。一旦侦听到有客户端应用程序请求连接侦听端口,服务器端应用将接受请求,并建立一个负责与客户端应用程序通信的信道,即通过创建连接套接字与客户端应用程序建立连接,由连接套接字完成与客户端应用程序的数据传送操作,服务器端应用程序继续侦听更多的客户端连接请求。TcpListener通过实例创建过程完成与本地网络接口的绑定,并由所创建的实例调用Start方法启动侦听;当侦听到客户端应用程序的连接请求后,根据客户端应用程序的不同请求方式,可以通过AcceptTcpClient方法接受传入的连接请求并创建TcpClient实例以处理请求,或者通过AcceptSocket方法接受传入的连接请求并创建Socket实例以处理请求,并由所创建的TcpClient实例或Socket实例完成与客户端应用程序的网络数据传输。最后,需要使用Stop关闭用于侦听传入连接的Socket,同时也必须关闭从AcceptSocket或AcceptTcpClient返回的任何实例,以释放相关资源。

流程:

1.创建TcpListener实例

      TcpListener类提供了3种构造函数的重载形式来创建TcpListener实例。

(1)TcpListener(port); //指定本机端口

(2)public TcpListener(IPEndPoint) //指定本机终结点

(3)public TcpListener(IPAddress,port) //指定本机IP地址及端口

 分别根据指定的侦听端口、IPEndPoint对象(包含了IP地址和端口号)、IPAddress对象和端口号来创建TcpListener实例,并且实现与默认端口或指定IP地址和端口的绑定,如:  m_host = IPAddress.Parse(m_serverIP); m_Listener = new TcpListener(m_host, m_port);

2.侦听

       创建TcpListener实例后,便可以调用Start方法启动侦听,即该方法将调用TcpListener实例的基础Socket上的Listen方法,开始侦听客户的连接请求,如:                       m_Listener.Start( );

3.接收连接请求

        当侦听到有客户连接请求时,可以使用AcceptSocket或AcceptTcpClient接收任何当前在队列中挂起的连接请求。这两种方法分别返回一个Socket或TcpClient实例以接受客户的连接请求,如:

                       TcpClient m_client = m_Listener.AcceptTcpClient( );

      通过返回的Socket或TcpClient实例来实现与提出连接请求的客户的单独网络数据传输。

4.收发数据

       如果接收连接请求时返回的是Socket实例,则可以用Send和Receive方法实现与客户的通信。如果返回的是TcpClient实例,则可以通过对NetworkStream的读写来实现与客户的数据通信。由于服务器可以同时与多个客户建立连接并进行数据通信,因此往往会引入多线程技术,为每个客户的连接建立一个线程,在该线程中实现与客户的数据通信。如下代码所示。

  //为每个客户连接创建并启动一个线程

  TcpClient m_client = m_Listener.AcceptTcpClient( );

  ClientHandle m_handle = new ClientHandle( );

  m_handle.ClientSocket = m_client;

  Thread m_clientthread = new Thread(new ThreadStart(m_handle.ResponseClient));

  m_clientthread.Start( ); 

//线程处理代码

public void ResponseClient( )

{

    if (m_clientsocket != null)

    {

      StreamReader rs = new StreamReader(m_clientsocket.GetStream( ));

        NetworkStream ws = m_clientsocket.GetStream( );

        ……

        while (true)

        {

             //接收信息

            m_returnData = rs.ReadLine( );

            ……

            //回送信息

            ws.Write(data, 0, data.Length);

            ……

        }

        m_clientsocket.Close( );

    }

}

5.关闭连接

        与客户程序通信完成之后,最后一步是停止侦听套接字,此时可以调用TcpListener的Stop方法来实现。

服务器端:

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

namespace Server
{
//客户连接处理,用来接收或发送网络数据
class ClientHandle

{
private string m_username;
private TcpClient m_clientSocket = null;
private string m_returnData, m_sendData;
byte[] data;//中间变量

public TcpClient ClientSocket//属性
{

get { return m_clientSocket; }
set { m_clientSocket = value; }
}

byte[] EncodingASCII(string buf)
{
byte[] data = Encoding.ASCII.GetBytes(buf+"\r\n");
return data;
}

public void ResponseClient()
{
if (m_clientSocket != null)
{
StreamReader rs = new StreamReader(m_clientSocket .GetStream() );
NetworkStream ws = m_clientSocket.GetStream();

//获取用户名
m_returnData = rs.ReadLine();

m_username = m_returnData;
m_sendData = "Welcome "+m_returnData +"to Server";
Console.WriteLine(m_sendData );//显示信息
//回送欢迎信息
data = EncodingASCII(m_sendData );

ws.Write(data,0,data.Length );

while (true)
{
//接收信息
m_returnData = rs.ReadLine();


//解释所接收的信息
if (m_returnData.IndexOf("QUIT") > -1)

{
Console.WriteLine(m_username +"has quited!");
break;
}
else if (m_returnData.IndexOf("GETDATE") > -1)
{
m_sendData = DateTime.Now.ToString();
}
else
{
m_sendData = "-->"+m_returnData ;
}
data = EncodingASCII(m_sendData );
ws.Write(data,0,data .Length);
}
m_clientSocket.Close();
}
}
}

class Server
{
static void Main(string[] args)
{
string m_serverIP = "127.0.0.1";
int m_port=5555;
bool rt = false;
TcpListener m_Listener = null;
IPAddress m_host;

if (args.Length < 2)
{
Console.WriteLine("Usage:Server ServerIP Port");
}
else
{
try
{
m_serverIP = args[0].ToString();
m_port = int.Parse(args[1].ToString ());
rt = true;
}
catch (Exception ex)
{
Console.WriteLine("Parameter Error:"+ex.Message );
}
}

if (rt)
{
try
{
m_host = IPAddress.Parse(m_serverIP );
m_Listener = new TcpListener(m_host ,m_port );

m_Listener.Start();
Console.WriteLine("Starting to listen....");

while (true)
{
TcpClient m_client = m_Listener.AcceptTcpClient();
ClientHandle m_handle = new ClientHandle();
m_handle.ClientSocket = m_client;

Thread m_clientthread = new Thread(new ThreadStart(m_handle.ResponseClient));
m_clientthread.Start();
}
m_Listener.Stop();
}
catch (Exception ex)
{
Console.WriteLine("Exception"+ex.Message );
}
}
}
}
}

客户端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net.Sockets;

namespace Client
{
//客户类
class Client

{
static byte[] EncodingASCII(string buf)
{
byte[] data = Encoding.ASCII.GetBytes(buf+"\r\n");
return data;
}

static void Main(string[] args)
{
string m_servername = "127.0.0.1";
string m_username = "Client";
int m_port = 5555;
TcpClient m_client;
bool rt = false;
string m_sendData, m_returnData;
byte[] data;
StreamReader rs;
NetworkStream ws;
if (args.Length < 3)
{
Console.WriteLine("Usage:Client UserName ServerName Port");
}
else
{
try//获取命令行参数
{

m_username = args[0].ToString();
m_servername = args[1].ToString();
m_port =int.Parse ( args[2].ToString ());
rt = true;
}
catch (Exception ex)
{
Console.WriteLine("Parameter Error:"+ex.Message );
}
}
if (rt)
{
try
{
//创建对象并提出连接请求
m_client = new TcpClient();

m_client.Connect(m_servername ,m_port );
rs = new StreamReader(m_client .GetStream() );
ws = m_client.GetStream();
//发送用户名
m_sendData = m_username;

data = EncodingASCII(m_sendData );
ws.Write(data ,0,data .Length );

while (true )
{
//获取返回信息并显示
m_returnData = rs.ReadLine();

Console.WriteLine(m_returnData );

//发送命令或其它信息
Console.WriteLine("Input data[GETDATE|QOIT|Other]:");

m_sendData =Console .ReadLine ();
if(m_sendData .IndexOf ("QUIT")>-1)
{
m_sendData ="QUIT";
}
else if(m_sendData .IndexOf ("GETDATE")>-1)
{
m_sendData ="GETDATE";
}
data=EncodingASCII (m_sendData );
ws.Write (data ,0,data.Length );
if(m_sendData .IndexOf ("QUIT")>-1)
break ;
}
m_client .Close ();
}
catch (Exception ex)
{
Console.WriteLine("Exception"+ex.Message );
}
}
}
}
}
posted on 2012-03-11 21:40  WaitingSky  阅读(499)  评论(0编辑  收藏  举报