Visual C#网络编程之TCP

支持Http、Tcp和Udp的类组成了TCP/IP三层模型(请求响应层、应用协议层、传输层)的中间层-应用协议层,该层的类比位于最底层的Socket类提供了更高层次的抽象,它们封装

TCP 和 UDP 套接字的创建,不需要处理连接的细节,这使得我们在编写套接字级别的协议时,可以更多地尝试使用 TCPClient 、

UDPClient和TcpListener,而不是直接向 Socket 中写。它们之间的这种层次关系示意如下:

可见,TcpClient 类基于 Socket 类构建,这是它能够以更高的抽象程度提供 TCP

服务的基础。正因为这样,许多应用层上的通讯协议,比如FTP(File Transfers Protocol)文件传输协议、HTTP(Hypertext

Transfers Protocol)超文本传输协议等都直接创建在TcpClient等类之上。

我们对C#语言基础教程了解多少,对Visual C#网络编程的TCP又了解多少呢?

TCPClient 类使用 TCP 从 Internet 资源请求数据。TCP 协议建立与远程终结点的连接,然后使用此连接发送和接收数据包。TCP

负责确保将数据包发送到终结点并在数据包到达时以正确的顺序对其进行组合。

从名字上就可以看出,TcpClient类专为客户端设计,它为 TCP 网络服务提供客户端连接。TcpClient

提供了通过网络连接、发送和接收数据的简单方法。

若要建立 TCP 连接,必须知道承载所需服务的网络设备的地址(IPAddress)以及该服务用于通讯的 TCP 端口 (Port)。Internet

分配号码机构 (Internet Assigned Numbers Authority, IANA) 定义公共服务的端口号(你可以访问

http://www.iana.org/assignments/port-numbers获得这方面更详细的资料)。IANA 列表中所没有的服务可使用 1,024

到 65,535 这一范围中的端口号。要创建这种连接,你可以选用TcpClient类的三种构造函数之一:

1、public

TcpClient()当使用这种不带任何参数的构造函数时,将使用本机默认的ip地址并将使用默认的通信端口号0。这样情况下,如果本机不止一个ip地址,将无法选择使用。以下语句示例了如何使用默认构造函数来创建新的

TcpClient:

TcpClient tcpClientC = new TcpClient();

2、public

TcpClient(IPEndPoint)使用本机IPEndPoint创建TcpClient的实例对象。上一篇介绍过了,IPEndPoint将网络端点表示为IP地址和端口号,在这里它用于指定在建立远程主机连接时所使用的本地网络接口(IP

地址)和端口号,这个构造方法为使用本机IPAddress和Port提供了选择余地。下面的语句示例了如何使用本地终结点创建 TcpClient 类的实例:

IPHostEntry ipInfo=Dns.GetHostByName("www.tuha.net");//主机信息

IPAddressList[] ipList=ipInfo.AddressList;//IP地址数组

IPAddress ip=ipList[0];//多IP地址时一般用第一个

IPEndPoint ipEP=new IPEndPoint(ip,4088);//得到网络终结点

try{

TcpClient tcpClientA = new TcpClient(ipLocalEndPoint);

}

catch (Exception e ) {

Console.WriteLine(e.ToString());

}

到这里,你可能会感到困惑,客户端要和服务端创建连接,所指定的IP地址及通信端口号应该是远程服务器的呀!事实上的确如此,使用以上两种构造函数,你所实现的只是TcpClient实例对象与IP地址和Port端口的绑定,要完成连接,你还需要显式指定与远程主机的连接,这可以通过TcpClient类的Connect方法来实现,

Connet方法使用指定的主机名和端口号将客户端连接到 远程主机:

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

public void Connect(IPAddress, int); 使用指定的 IP 地址和端口号将客户端连接到 TCP 主机。

public void Connect(string, int); 将客户端连接到指定主机上的指定端口。

需要指出的是,Connect方法的所有重载形式中的参数IPEndPoint网络终结点、IPAddress以及表现为string的Dns主机名和int指出的Port端口均指的是远程服务器。

以下示例语句使用主机默认IP和Port端口号0与远程主机建立连接:

TcpClient tcpClient = new TcpClient();//创建TcpClient对象实例

try{

tcpClient.Connect("www.contoso.com",11002);//建立连接

}

catch (Exception e ){

Console.WriteLine(e.ToString());

}

3、public TcpClient(string, int);初始化 TcpClient

类的新实例并连接到指定主机上的指定端口。与前两个构造函数不一样,这个构造函数将自动建立连接,你不再需要额外调用Connect方法,其中string类型的参数表示远程主机的Dns名,如:www.tuha.net。

以下示例语句调用这一方法实现与指定主机名和端口号的主机相连:

try{

TcpClient tcpClientB = new TcpClient("www.tuha.net", 4088);

}

catch (Exception e ) {

Console.WriteLine(e.ToString());

}

前面我们说,TcpClient类创建在Socket之上,在Tcp服务方面提供了更高层次的抽象,体现在网络数据的发送和接受方面,是TcpClient使用标准的Stream流处理技术,使得它读写数据更加方便直观,同时,.Net框架负责提供更丰富的结构来处理流,贯穿于整个.Net框架中的流具有更广泛的兼容性,构建在更一般化的流操作上的通用方法使我们不再需要困惑于文件的实际内容(HTML、XML

或其他任何内容),应用程序都将使用一致的方法(Stream.Write、Stream.Read) 发送和接收数据。另外,流在数据从 Internet

下载的过程中提供对数据的即时访问,可以在部分数据到达时立即开始处理,而不需要等待应用程序下载完整个数据集。.Net中通过NetworkStream类实现了这些处理技术。

NetworkStream 类包含在.Net框架的System.Net.Sockets

命名空间里,该类专门提供用于网络访问的基础数据流。NetworkStream 实现通过网络套接字发送和接收数据的标准.Net

框架流机制。NetworkStream 支持对网络数据流的同步和异步访问。NetworkStream 从 Stream

继承,后者提供了一组丰富的用于方便网络通讯的方法和属性。

同其它继承自抽象基类Stream的所有流一样,NetworkStream网络流也可以被视为一个数据通道,架设在数据来源端(客户Client)和接收端(服务Server)之间,而后的数据读取及写入均针对这个通道来进行。

.Net框架中,NetworkStream流支持两方面的操作:

1、写入流。写入是从数据结构到流的数据传输。

2、读取流。读取是从流到数据结构(如字节数组)的数据传输。

与普通流Stream不同的是,网络流没有当前位置的统一概念,因此不支持查找和对数据流的随机访问。相应属性CanSeek 始终返回 false,而

Seek 和 Position 方法也将引发 NotSupportedException。

基于Socket上的应用协议方面,你可以通过以下两种方式获取NetworkStream网络数据流:

1、使用NetworkStream构造函数:public NetworkStream(Socket, FileAccess,

bool);(有重载方法),它用指定的访问权限和指定的 Socket 所属权为指定的 Socket 创建 NetworkStream

类的新实例,使用前你需要创建Socket对象实例,并通过Socket.Connect方法建立与远程服务端的连接,而后才可以使用该方法得到网络传输流。示例如下:

Socket s=new

Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//创建客户端Socket对象实例

try{

s.Connect("www.tuha.net",4088);//建立与远程主机的连接

}

catch(Exception e){

MessageBox.show("连接错误:" +e.Message);

}

try{

NetworkStream stream=new

NetworkStream(s,FileAccess.ReadWrite,false);//取得网络传输流

}

2、通过TcpClient.GetStream方法:public NetworkStream

etStream();它返回用于发送和接收数据的基础网络流NetworkStream。GetStream 通过将基础 Socket 用作它的构造函数参数来创建

NetworkStream 类的实例。使用前你需要先创TcpClient对象实例并建立与远程主机的连接,示例如下:

TcpClient tcpClient = new TcpClient();//创建TcpClient对象实例

Try{

tcpClient.Connect("www.tuha.net",4088);//尝试与远程主机相连

}

catch(Exception e){

MessageBox.Show("连接错误:"+e.Message);

}

try{

NetworkStream stream=tcpClient.GetStream();//获取网络传输流

}

catch(Exception e)

{

MessageBox.Show("TcpClient错误:"+e.Message);

}

通过以上方法得到NetworkStream网络流之后,你就可以使用标准流读写方法Write和Read来发送和接受数据了。

以上是.Net下使用TcpClient类实现客户端编程的技术资料,为了向客户端提供这些服务,我们还需要编制相应的服务端程序,前一篇《Visual

C#.Net网络程序开发-Socket篇》上曾经提到,

Socket作为其他网络协议的基础,既可以面向客户端开发,也可以面向服务端开发,在传输层面上使用较多,而在应用协议层面上,客户端我们采用构建于Socket类之上的TcpClient取代Socket;相应地,构建于Socket之上的TcpListener提供了更高理念级别的

TCP 服务,使得我们能更方便地编写服务端应用程序。正是因为这样的原因,像FTP 和 HTTP 这样的应用层协议都是在 TcpListener

类的基础上建立的。

.Net中的TCPListener 用于监视TCP

端口上的传入请求,通过绑定本机IP地址和相应端口(这两者应与客户端的请求一致)创建TcpListener对象实例,并由Start方法启动侦听;当TcpListener侦听到用户端的连接后,视客户端的不同请求方式,通过AcceptTcpClient

方法接受传入的连接请求并创建 TcpClient 以处理请求,或者通过AcceptSocket 方法接受传入的连接请求并创建 Socket

以处理请求。最后,你需要使用 Stop 关闭用于侦听传入连接的 Socket,你必须也关闭从 AcceptSocket 或 AcceptTcpClient

返回的任何实例。这个过程详细解说如下:

首先,创建TcpListener对象实例,这通过TcpListener类的构造方法来实现:

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

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

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

以上方法中的参数在前面多次提到,这里不再细述,唯一需要提醒的是,这些参数均针对服务端主机。下面的示例演示创建 TcpListener

类的实例:

IPHostEntry ipInfo=Dns.Resolve("127.0.0.1");//主机信息

IPAddressList[] ipList=ipInfo.IPAddressList;//IP数组

IPAddress ip=ipList[0];//IP

try{

TcpListener tcpListener = new TcpListener(ipAddress,

4088);//创建TcpListener对象实例以侦听用户端连接

}

catch ( Exception e){

MessageBox.Show("TcpListener错误:"+e.Message);

}

随后,你需要调用Start方法启动侦听:

public void Start();

其次,当侦听到有用户端连接时,需要接受挂起的连接请求,这通过调用以下两方法之一来完成连接:

public Socket AcceptSocket();

public TcpClient AcceptTcpClient();

前一个方法返回代表客户端的Socket对象,随后可以通过Socket 类的 Send 和 Receive

方法与远程计算机通讯;后一个方法返回代表客户端的TcpClient对象,随后使用上面介绍的 TcpClient.GetStream 方法获取 TcpClient

的基础网络流 NetworkStream,并使用流读写Read/Write方法与远程计算机通讯。

最后,请记住关闭侦听器:public void Stop();

同时关闭其他连接实例:public void Close();

下面的示例完整体现了上面的过程:

bool done = false;

TcpListener listener = new TcpListener(13);//

创建TcpListener对象实例(13号端口提供时间服务)

listener.Start();//启动侦听

while (!done) {//进入无限循环以侦听用户连接

TcpClient client = listener.AcceptTcpClient();//侦听到连接后创建客户端连接TcpClient

NetworkStream ns = client.GetStream();//得到网络传输流

byte[] byteTime =

Encoding.ASCII.GetBytes(DateTime.Now.ToString());//预发送的内容(此为服务端时间)转换为字节数组以便写入流

try {

ns.Write(byteTime, 0, byteTime.Length);//写入流

ns.Close();//关闭流

client.Close();//关闭客户端连接

}

catch (Exception e) {

MessageBox.Show("流错误:"+e.Message)

}

综合运用上面的知识,下面的实例实现了简单的网络通讯-双机互连,针对客户端和服务端分别编制了应用程序。客户端创建到服务端的连接,向远程主机发送连接请求连接信号,并发送交谈内容;远程主机端接收来自客户的连接,向客户端发回确认连接的信号,同时接收并显示客户端的交谈内容。在这个基础上,发挥你的创造力,你完全可以开发出一个基于程序语言(C#)级的聊天室!

客户端主要源代码:

public void SendMeg()//发送信息

{

try

{

int port=Int32.Parse(textBox3.Text.ToString());//远程主机端口

try

{

tcpClient=new TcpClient(textBox1.Text,port);//创建TcpClient对象实例 }

catch(Exception le)

{

MessageBox.Show("TcpClient Error:"+le.Message);

}

string strDateLine=DateTime.Now.ToShortDateString()+"

"+DateTime.Now.ToLongTimeString();//得到发送时客户端时间

netStream=tcpClient.GetStream();//得到网络流

sw=new StreamWriter(netStream);//创建TextWriter,向流中写字符

string words=textBox4.Text;//待发送的话

string content=strDateLine+words;//待发送内容

sw.Write(content);//写入流

sw.Close();//关闭流写入器

netStream.Close();//关闭网络流

tcpClient.Close();//关闭客户端连接

}

catch(Exception ex)

{

MessageBox.Show("Sending Message Failed!"+ex.Message);

}

textBox4.Text="";//清空

}

服务器端主要源代码:

public void StartListen()//侦听特定端口的用户请求

{

//ReceiveMeg();

isLinked=false; //连接标志

try

{

int port=Int32.Parse(textBox1.Text.ToString());//本地待侦听端口

serverListener=new TcpListener(port);//创建TcpListener对象实例

serverListener.Start(); //启动侦听

}

catch(Exception ex)

{

MessageBox.Show("Can‘t Start Server"+ex.Message);

return;

}

isLinked=true;

while(true)//进入无限循环等待用户端连接

{

try

{

tcpClient=serverListener.AcceptTcpClient();//创建客户端连接对象

netStream=tcpClient.GetStream();//得到网络流

sr=new StreamReader(netStream);//流读写器

}

catch(Exception re)

{

MessageBox.Show(re.Message);

}

string buffer="";

string received="";

received+=sr.ReadLine();//读流中一行

while(received.Length!=0)

{

buffer+=received;

buffer+="\r\n";

//received="";

received=sr.ReadLine();

}

listBox1.Items.Add(buffer);//显示

//关闭

sr.Close();

netStream.Close();

tcpClient.Close();

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容

  • 1 网络编程----TCPNo24 【 public class Server { public static...
    征程_Journey阅读 1,234评论 0 4
  • 1、TCP状态linux查看tcp的状态命令:1)、netstat -nat 查看TCP各个状态的数量2)、lso...
    北辰青阅读 9,384评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • R小姐是个典型的金牛座,她固执,死心眼,像牛一样倔强。 她认定的事,就算所有人都反对她还是会义无反顾地去干。 她喜...
    奕星阅读 282评论 1 2
  • 一 培训完后正式上班。我的班次是下午班,4点到凌晨1点。只有几天,然后就是两个星期的大夜班,夜晚12点到第二天早上...
    林Carols阅读 326评论 0 2