C#網絡編程.套接字.TcpListener.TcpClient


本文主要講述了基於套接字(Socket)進行網絡編程的基本概念,其中包括TCP協議、套接字,以及兩個基本操作:偵聽端口、連接遠程服務端。


 

TCP是面向連接的,它的意思是說兩個遠程主機(或者叫進程,因為實際上遠程通信是進程之間的通信,而進程則是運行中的程序),必須首先進行一個握手過程,確認連接成功,之后才能傳輸實際的數據。比如說進程A想將字符串“It's a rainy world”發給進程B,它首先要建立連接。在這一過程中,它首先需要知道進程B的位置(主機地址和端口號)。隨后發送一個不包含實際數據的請求報文,我們可以將這個報文稱之為“hello”。如果進程B接收到了這個“hello”,就向進程A回復一個“hello”,進程A隨后才發送實際的數據“It's a rainy world”。

關於TCP第二個需要了解的,就是它是全雙工的。意思是說如果兩個主機上的進程(比如進程A、進程B),一旦建立好連接,那么數據就既可以由A流向B,也可以由B流向A。除此以外,它還是點對點的,意思是說一個TCP連接總是兩者之間的,在發送中,通過一個連接將數據發給多個接收方是不可能的。TCP還有一個特性,就是稱為可靠的數據傳輸,意思是連接建立后,數據的發送一定能夠到達,並且是有序的,就是說發的時候你發了ABC,那么收的一方收到的也一定是ABC,而不會是BCA或者別的什么。

編程中與TCP相關的最重要的一個概念就是套接字。我們應該知道網絡七層協議,如果我們將上面的應用程、表示層、會話層籠統地算作一層(有的教材便是如此划分的),那么我們編寫的網絡應用程序就位於應用層,而大家知道TCP是屬於傳輸層的協議,那么我們在應用層如何使用傳輸層的服務呢(消息發送或者文件上傳下載)?大家知道在應用程序中我們用接口來分離實現,在應用層和傳輸層之間,則是使用套接字來進行分離。它就像是傳輸層為應用層開的一個小口,應用程序通過這個小口向遠程發送數據,或者接收遠程發來的數據;而這個小口以內,也就是數據進入這個口之后,或者數據從這個口出來之前,我們是不知道也不需要知道的,我們也不會關心它如何傳輸,這屬於網絡其它層次的工作。 (舉個例子,如果你想寫封郵件發給遠方的朋友,那么你如何寫信、將信打包,屬於應用層,信怎么寫,怎么打包完全由我們做主;而當我們將信投入郵筒時,郵筒的那個口就是套接字,在進入套接字之后,就是傳輸層、網絡層等(郵局、公路交管或者航線等)其它層次的工作了。我們從來不會去關心信是如何從西安發往北京的,我們只知道寫好了投入郵筒就OK了。 )


接下來介紹下,在C#中如何進行網絡編程

服務端

第一步就是開啟對本地機器上某一端口的偵聽。首先創建一個控制台應用程序,將項目名稱命名為ServerConsole,它代表我們的服務端。如果想要與外界進行通信,第一件要做的事情就是開啟對端口的偵聽,這就像為計算機打開了一個“門”,所有向這個“門”發送的請求(“敲門”)都會被系統接收到。在C#中可以通過下面幾個步驟完成,首先使用本機Ip地址和端口號創建一個System.Net.Sockets.TcpListener類型的實例,然后在該實例上調用Start()方法,從而開啟對指定端口的偵聽。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
 
namespace SocksTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Server is running ... ");
            IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });
            TcpListener listener = new TcpListener(ip, 8500);
 
            listener.Start();           // 開始偵聽
            Console.WriteLine("Start Listening ...");
 
            TcpClient remoteClient = listener.AcceptTcpClient();//接受掛起的連接請求
            Console.WriteLine("Client Connected!{0} <-- {1}",
                remoteClient.Client.LocalEndPoint.ToString(),remoteClient.Client.RemoteEndPoint.ToString());
            Console.Read();
        }
    }
}

 

面的代碼中,我們開啟了對8500端口的偵聽。在運行了上面的程序之后,然后打開“命令提示符”,輸入“netstat-a”,可以看到計算機器中所有打開的端口的狀態。可以從中找到8500端口,看到它的狀態是LISTENING,這說明它已經開始了偵聽:

image

 

客戶端:

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

namespace SocksClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Client is running......");
            TcpClient tcpClient = new TcpClient();
            try
            {
                tcpClient.Connect("localhost", 8500);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                Console.Read();
                return;
            }
            Console.WriteLine("Server Connected!{0} --> {1}",
                tcpClient.Client.LocalEndPoint.ToString(),tcpClient.Client.RemoteEndPoint.ToString());
            Console.Read();
        }
    }
}

 

當開啟了server,然后開啟client,server上會顯示連接上的狀態。

image

image

 


接下來做的是獲取多客戶端連接

修改后的客戶端代碼

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

namespace SocksClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Client is running......");
            TcpClient tcpClient;
            for (int i = 0; i < 5; i++)
            {
                try
                {
                    tcpClient = new TcpClient();
                    tcpClient.Connect("localhost", 8500);

                    Console.WriteLine("Server Connected!{0} --> {1}",
                        tcpClient.Client.LocalEndPoint.ToString(), tcpClient.Client.RemoteEndPoint.ToString());
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    Console.Read();
                    return;
                }
            }
            Console.Read();
        }
    }
}

 

修改后的服務端代碼

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

namespace SocksTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Server is running ... ");
            IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });
            TcpListener listener = new TcpListener(ip, 8500);

            listener.Start();           // 開始偵聽
            Console.WriteLine("Start Listening ...");

            while (true)
            {
                TcpClient remoteClient = listener.AcceptTcpClient();//接受掛起的連接請求
                Console.WriteLine("Client Connected!{0} <-- {1}",
                    remoteClient.Client.LocalEndPoint.ToString(), remoteClient.Client.RemoteEndPoint.ToString());
            }
            Console.Read();
        }
    }
}

 

運行后的效果

image

 

微軟對以上做了很好的封裝, 這里用起來很簡單.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM