天天看點

C#程式設計入門_網絡程式設計_21

21篇C#部落格的配套源碼

網絡基本原理

C#程式設計入門_網絡程式設計_21

ISO:國際标準化組織

OSI:開放系統互聯結構模型

ISO/OSI模型把網絡分成了若幹層,每層都實作特定的功能。

ISO/OSI模型把網絡表示成豎直的線,模型中的每一層次至少包含有一個協定,是以也可以說是模型中的協定是逐個疊放的。協定棧是個由豎直的層和對方的協定抽象而來。

OSI不是一個實際的實體模型,而是一個将網絡協定規範化了的邏輯參考模型

網絡通訊原理

C#程式設計入門_網絡程式設計_21

TCP程式設計

TCP協定建立連接配接的簡圖

C#程式設計入門_網絡程式設計_21

用戶端和伺服器履歷連接配接的過程

C#程式設計入門_網絡程式設計_21

關閉TCP的四次揮手

C#程式設計入門_網絡程式設計_21

服務端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace TcpServer
{
    class Program
    {
        static TcpListener server;
        static void Main(string[] args)
        {
            IPAddress ip = IPAddress.Parse("127.0.0.1");
            server = new TcpListener(ip,);
            server.Start();

            Thread th = new Thread(ReciveMsg);
            th.Start();

        }
        static void ReciveMsg()
        {
            try
            {
                while (true)
                {
                    TcpClient client = server.AcceptTcpClient();
                    StreamReader sr = new StreamReader(client.GetStream());
                    string str = sr.ReadLine();
                    Console.WriteLine("收到來自用戶端的資訊是:" + str);
                }
            }
            catch (Exception)
            {


            }
        }
        static void Send(object o)
        {
            TcpClient client = o as TcpClient;
            StreamWriter sw = new StreamWriter(client.GetStream());
            string str = Console.ReadLine();
            if (str!=null)
            {
                sw.WriteLine(str);
            }
            sw.Flush();
            sw.Close();
        }
    }
}
           

用戶端:

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

namespace TcpClientDemo
{
    class Program
    {
        static TcpClient client;
        static void Main(string[] args)
        {

            try
            {
                while (true)
                {
                    client = new TcpClient("127.0.0.1", );
                    StreamWriter sw = new StreamWriter(client.GetStream());
                    string str = Console.ReadLine();
                    sw.WriteLine(str);
                    sw.Flush();
                    sw.Close();

                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);

            }

            Console.ReadLine();
        }


        static void RecMsg()
        {
            try
            {
                StreamReader sr = new StreamReader(client.GetStream());
                string str = string.Empty;
                if ((str = sr.ReadLine())!=null)
                {
                    Console.WriteLine("來自伺服器端的資訊是:" + str);
                }

                sr.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        }
    }
}
           

UDP程式設計

C#程式設計入門_網絡程式設計_21
  • UTP簡介

    雖然和TCP一樣也建構與IP之上,但UDP作為一種簡單的、面向資料報的無連接配接協定,提供的是不一定可靠的傳輸服務。所謂的“無連接配接”是指在正式通信前不必與對方先建立連接配接,不管對方狀态如何都直接發送過去。這與發送機短信非常的相似,隻要發往對方的手機号就可以了,不用考慮對方手機狀态。

  • UDP原理

    UDP将網絡資料流量壓縮成資料報的形式,每一個資料報用8個位元組描述報頭資訊,剩餘位元組包含具體的傳輸資料,UDP報頭很短,相對于TCP的20位元組資訊包含的額外開銷很小,報頭由4個域組成,其中每個域各占用2個位元組,具體為元端口,目的端口,使用者資料報長和檢驗和。

    UDP協定使用端口号為不同的應用保留其各自的資料傳輸通道。UDP和TCP協定正是采用這一機制對同一時刻多種應用同時發送和接收資料實作支援。資料發送方(用戶端或伺服器)将UDP資料報通過源端口發送出去,而資料接收方則通過目标端口接收資料。

    有的網絡應用智能使用預先為其預留或注冊的靜态端口(如HTTP用80端口,FTP使用21端口)而另外一些網絡應用則可以使用未被注冊的動态端口。因為UDP報頭使用兩個位元組(1個位元組8位)存放端口号,是以端口号的有效範圍從0到65535.一般來說,大于49151的端口号都代表動态端口。

UDP和TCP的差別

UDP和TCP的主要差別在是二者在如何實作資訊的可靠傳遞方面存在不同,具體表現為以下幾點:

  • UDP可靠性不如TCP

    TCP包含了專門的傳遞保證機制,當資料接收方收到發送方傳來的資訊時,會自動向發送方發出确認消息;發送方隻有在接收到該确認消息之後才繼續傳遞其他消息,否則将一直等待,直到收到确認資訊為止。與TCP不同,UDP并不提供資料傳達的保證機制。如果在發送方到接收方的傳遞過程中出現資料包的丢失,協定本身并不能做出任何檢測或提示。是以人們把UDP稱為不可靠的傳輸協定。

  • UDP不能保證有序傳輸

    UDP不能確定資料的發送和接收順序。對于突發性的資料報,有可能會亂序。不過,事實上UDP的這種亂序基本上很少出現,通常隻會在網絡非常擁擠的情況下才有可能發生。

UDP的優勢

說了這麼多UDP的缺點,那使用它還有什麼價值麼?

從應用角度考慮,UDP相比TCP的優勢,主要表現在以下幾個方面。

  • UDP速度比TCP要快
  • UDP有消息邊界
  • UDP可以一對多傳輸

    服務端:

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

namespace UDPServer
{
    class Program
    {
        static void Main(string[] args)
        {
            UdpClient udpRec = new UdpClient();

            try
            {
                while (true)
                {
                    IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, );
                    byte[] recBytes = udpRec.Receive(ref remoteIpEndPoint);
                    string returnData = Encoding.Default.GetString(recBytes);
                    Console.WriteLine("接收到的資料是:" + returnData);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                udpRec.Close();
            }
        }
    }
}
           

用戶端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace UDPClientDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            UdpClient client = new UdpClient("127.0.0.1", );

            try
            {
                while (true)
                {
                    string str = Console.ReadLine();
                    byte[] sendBytes = Encoding.Default.GetBytes(str);
                    client.Send(sendBytes, sendBytes.Length);
                }
            }
            catch (Exception e)
            {

                Console.WriteLine(e);
            }
            finally
            {
                client.Close();
            }
            Console.Read();
        }
    }
}
           

Socket程式設計

Scoket TCP程式設計的流程圖

C#程式設計入門_網絡程式設計_21

服務端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace NetWork
{
    class Program
    {
        static Socket severSocket;
        static Thread recThread;
        static void Main(string[] args)
        {
            severSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipPoint = new IPEndPoint(ip, );

            try
            {
                severSocket.Bind(ipPoint);
                severSocket.Listen();
                recThread = new Thread(Listen);
                recThread.Start();

            }
            catch (SocketException se)
            {

                Console.WriteLine(se.Message);
            }
        }


        static void Listen()
        {
            while (true)
            {
                Socket client = severSocket.Accept();
                IPEndPoint ipEndPoint = (IPEndPoint)client.RemoteEndPoint;
                string info = "用戶端的ip位址是:"+ipEndPoint.Address + "  用戶端的端口号:" + ipEndPoint.Port;

                Thread recThread = new Thread(RecMsg);
                recThread.IsBackground = true;
                recThread.Start(client);
            }
        }

        static void RecMsg(object o)
        {
            try
            {
                byte[] buffer = new byte[];
                Socket client = o as Socket;
                IPEndPoint ip = client.RemoteEndPoint as IPEndPoint;

                while (true)
                {
                    int len = client.Receive(buffer);
                    if (len<=)
                    {
                        return;
                    }
                    string info = Encoding.Default.GetString(buffer,,len);
                    Console.WriteLine("收到來自用戶端"+ip.Address+"  "+ip.Port+"的資訊:"+info);

                    //回複收到的消息
                    Thread sendThread = new Thread(Send);
                    sendThread.IsBackground = true;
                    sendThread.Start(client);
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine(se.Message);
            }
        }


        static void Send(object o)
        {
            byte[] buffer = Encoding.Default.GetBytes(Console.ReadLine());
            Socket sc = o as Socket;
            try
            {
                sc.Send(buffer);
            }
            catch (SocketException se)
            {

                Console.WriteLine(se);
            }
        }

        ~Program()
        {
            severSocket.Disconnect(false);
        }

    }
}
           

用戶端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace NetWorkClient
{

    class Program
    {
        static Socket clientSocket;
        static Thread recThread;
        static void Main(string[] args)
        {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipa = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndpoint = new IPEndPoint(ipa,);
            clientSocket.Connect(ipEndpoint);

            //接收資料
            recThread = new Thread(RecMsg);
            recThread.IsBackground = true;
            recThread.Start();

            //避免 控制台程式啟動後
            while (true)
            {
                Send();
            }
        }

        static void RecMsg()
        {
            byte[] buffer = new byte[];
            while (true)
            {
                try
                {
                    int len = clientSocket.Receive(buffer);
                    if (len<=)
                    {
                        return;
                    }
                    string info = Encoding.Default.GetString(buffer,,len);
                    Console.WriteLine("收到來自服務端的資料:"+info);
                }
                catch (SocketException se)
                {

                    Console.WriteLine(se);
                }
            }
        }

        static void Send()
        {
            byte[] byteArr = Encoding.Default.GetBytes(Console.ReadLine());
            try
            {
                clientSocket.Send(byteArr);
            }
            catch (SocketException se)
            {
                Console.WriteLine(se);
            }
        }


    }
}
           

Scoket UDP程式設計的流程圖

C#程式設計入門_網絡程式設計_21