最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c# 網(wǎng)絡(luò)編程之tcp

 更新時(shí)間:2021年02月19日 10:46:56   作者:seabluescn  
這篇文章主要介紹了c# 網(wǎng)絡(luò)編程之tcp的的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下

一、概述

UDP和TCP是網(wǎng)絡(luò)通訊常用的兩個(gè)傳輸協(xié)議,C#一般可以通過Socket來實(shí)現(xiàn)UDP和TCP通訊,由于.NET框架通過UdpClient、TcpListener 、TcpClient這幾個(gè)類對Socket進(jìn)行了封裝,使其使用更加方便, 本文就通過這幾個(gè)封裝過的類講解一下相關(guān)應(yīng)用。

二、基本應(yīng)用:連接、發(fā)送、接收

服務(wù)端建立偵聽并等待連接:

TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9000);
tcpListener.Start();
if (tcpListener.Pending())
{
   TcpClient client = tcpListener.AcceptTcpClient();
   Console.WriteLine("Connected"); 
}

服務(wù)端是通過AcceptTcpClient方法獲得TcpClient對象,而客戶端是直接創(chuàng)建TcpClient對象。

TcpClient tcpClient = new TcpClient();
tcpClient.Connect("127.0.0.1", 9000);

發(fā)送數(shù)據(jù)TcpClient對象創(chuàng)建后,發(fā)送接收都通過TcpClient對象完成。

發(fā)送數(shù)據(jù):

TcpClient tcpClient = new TcpClient();
    tcpClient.Connect("127.0.0.1", 9000);
    NetworkStream netStream = tcpClient.GetStream();

    int Len = 1024;
    byte[] datas = new byte[Len];

    netStream.Write(datas, 0, Len);    

    netStream.Close();
    tcpClient.Close();

接收數(shù)據(jù):

TcpClient client = tcpListener.AcceptTcpClient();
Console.WriteLine("Connected"); 
 
 NetworkStream stream = client.GetStream();
 var remote = client.Client.RemoteEndPoint;

 byte[] data = new byte[1024];
 while (true)
 {
   if (stream.DataAvailable)
   {
    int len = stream.Read(data, 0, 1024);
    Console.WriteLine($"From:{remote}:Received ({len})");
   }
  Thread.Sleep(1);
 }

三、 粘包問題

和UDP不太一樣,TCP連接不會丟包,但存在粘包問題。(嚴(yán)格來說粘包這個(gè)說法是不嚴(yán)謹(jǐn)?shù)?,因?yàn)門CP通訊是基于流的,沒有包的概念,包只是使用者自己的理解。) 下面分析一下粘包產(chǎn)生的原因及解決辦法。

TCP數(shù)據(jù)通訊是基于流來實(shí)現(xiàn)的,類似一個(gè)隊(duì)列,當(dāng)有數(shù)據(jù)發(fā)送過來時(shí),操作系統(tǒng)就會把發(fā)送過來的數(shù)據(jù)依次放到這個(gè)隊(duì)列中,對發(fā)送者而言,數(shù)據(jù)是一片一片發(fā)送的,所以自然會認(rèn)為存在數(shù)據(jù)包的概念,但對于接收者而言,如果沒有及時(shí)去取這些數(shù)據(jù),這些數(shù)據(jù)依次存放在隊(duì)列中,彼此之間并無明顯間隔,自然就粘包了。

還有一種情況粘包是發(fā)送端造成的,有時(shí)我們調(diào)用發(fā)送代碼時(shí),操作系統(tǒng)可能并不會立即發(fā)送,而是放到緩存區(qū),當(dāng)緩存區(qū)達(dá)到一定數(shù)量時(shí)才真正發(fā)送。 

要解決粘包問題,大致有以下幾個(gè)方案。

1、 約定數(shù)據(jù)長度,發(fā)送端的數(shù)據(jù)都是指定長度,比如1024;接收端取數(shù)據(jù)時(shí)也取同樣長度,不夠長度就等待,保證取到的數(shù)據(jù)和發(fā)送端一致;

2、 接收端取數(shù)據(jù)的頻率遠(yuǎn)大于發(fā)送端,比如發(fā)送端每1秒發(fā)送一段數(shù)據(jù),接收端每0.1秒去取一次數(shù)據(jù),這樣基本可以保證數(shù)據(jù)不會粘起來;

以上兩個(gè)方案都要求發(fā)送端需要立即發(fā)送,不可緩存數(shù)據(jù)。而且這兩種方案都有缺陷:首先,第一種方案:如果要包大小一致的話,如果約定的包比較大,肯定有較多數(shù)據(jù)冗余,浪費(fèi)網(wǎng)絡(luò)資源,如果包較小,連接就比較頻繁,效率不高。

其次,第二種方案:這個(gè)方案只能在理想環(huán)境下可以實(shí)現(xiàn),當(dāng)服務(wù)端遭遇一段時(shí)間的計(jì)算壓力時(shí)可能會出現(xiàn)意外,不能完全保證。

比較完善的解決方案就是對接收到的數(shù)據(jù)進(jìn)行預(yù)處理:首先通過定義特殊的字符組合作為包頭和包尾,如果傳輸ASCII字符,可以用0x02表示開始(STX),用0x03表示結(jié)束(ETX),比如:STX ‘H' ‘e' ‘l' ‘l' ‘o' ETX (二進(jìn)制數(shù)據(jù): 02 48 65 6C 6C 6F 03)。如果數(shù)據(jù)較長可以在包頭留出固定位置存放包長度, 如:

02 00 05 48 65 6C 6C 6F 03

其中02 05 就表示正文長度為5個(gè)字節(jié),可以進(jìn)行校驗(yàn)。

雖然第三種方案比較嚴(yán)謹(jǐn),但相對復(fù)雜,在傳輸比較可靠、應(yīng)用比較簡單的場景下,也可以采用前面兩種解決方案。

四、 一個(gè)完整的例程

服務(wù)端:

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

namespace TCPServer
{
 class Program
 { 
  static void Main(string[] args)
  { 
   TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9000);
   tcpListener.Start();

   while (true)
   {
    if (tcpListener.Pending())
    {
     TcpClient client = tcpListener.AcceptTcpClient();
     Console.WriteLine("Connected");     

     Task.Run(() =>
     { 
      NetworkStream stream = client.GetStream();
      var remote = client.Client.RemoteEndPoint;
      
      while (true)
      {
       if (stream.DataAvailable)
       {
        byte[] data = new byte[1024];
        int len = stream.Read(data, 0, 1024);
        string Name = Encoding.UTF8.GetString(data,0,len);
        var senddata = Encoding.UTF8.GetBytes("Hello:" + Name);
        stream.Write(senddata, 0, senddata.Length);
       }

       if (!client.IsOnline())
       {
        Console.WriteLine("Connect Closed.");
        break;
       }

       Thread.Sleep(1);
      }
     });
    }

    Thread.Sleep(1);
   }
  }
 }

 public static class TcpClientEx
 {
  public static bool IsOnline(this TcpClient client)
  {
   return !((client.Client.Poll(15000, SelectMode.SelectRead) && (client.Client.Available == 0)) || !client.Client.Connected);
  }
 }
}

客戶端:

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

namespace TCP_Clent
{
 class Program
 {
  static void Main(string[] args)
  {
   ThreadPool.SetMinThreads(100, 100);
   ThreadPool.SetMaxThreads(200, 200); 

   Parallel.For(1, 10, x =>
   {
    SendData("Tom");
   });

   Console.WriteLine("All Completed!");
   Console.ReadKey();
  }

  private static void SendData(string Name)
  {
   Task.Run(() =>
   {
    Console.WriteLine("Start");
    TcpClient tcpClient = new TcpClient();
    tcpClient.Connect("127.0.0.1", 9000);
    Console.WriteLine("Connected");
    NetworkStream netStream = tcpClient.GetStream();

    Task.Run(() =>
    {
     Thread.Sleep(100);
     while (true)
     {
      if (!tcpClient.Client.Connected)
      {
       break;
      }

      if (netStream == null)
      {
       break;
      }

      try
      {
       if (netStream.DataAvailable)
       {
        byte[] data = new byte[1024];
        int len = netStream.Read(data, 0, 1024);
        var message = Encoding.UTF8.GetString(data, 0, len);
        Console.WriteLine(message);
       }
      }
      catch
      {
       break;
      }

      Thread.Sleep(10);
     }
    });

    for (int i = 0; i < 100; i++)
    {
     byte[] datas = Encoding.UTF8.GetBytes(Name);
     int Len = datas.Length;
     netStream.Write(datas, 0, Len);
     Thread.Sleep(1000);
    }

    netStream.Close();
    netStream = null;
    tcpClient.Close();

    Console.WriteLine("Completed");
   });
  }  
 }
}

傳送門:

C#網(wǎng)絡(luò)編程入門系列包括三篇文章:

(一)C#網(wǎng)絡(luò)編程入門之UDP

(二)C#網(wǎng)絡(luò)編程入門之TCP

(三)C#網(wǎng)絡(luò)編程入門之HTTP

以上就是c# 網(wǎng)絡(luò)編程之tcp的詳細(xì)內(nèi)容,更多關(guān)于c# 網(wǎng)絡(luò)編程tcp的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

城口县| 长宁区| 沙坪坝区| 天全县| 米脂县| 清苑县| 六安市| 固镇县| 克什克腾旗| 阜平县| 麻栗坡县| 介休市| 忻州市| 元朗区| 贺州市| 高要市| 莆田市| 佳木斯市| 谢通门县| 韩城市| 阿合奇县| 西充县| 凤山市| 沛县| 汤阴县| 乐东| 巩留县| 赤水市| 莲花县| 林州市| 东台市| 徐州市| 武山县| 霍林郭勒市| 涟水县| 石河子市| 江永县| 巫溪县| 肥西县| 九江县| 扶风县|