C# :雙向P2P聊天程式

基礎篇

C# 簡介

開發環境

變數與運算

流程控制

陣列

函數

物件

例外處理

函式庫篇

檔案處理

資料結構

正規表達式

Thread

應用篇

視窗程式

媒體影音

網路程式

遊戲程式

手機程式

資料庫

雲端運算

特殊功能

委派

擴展方法

序列化

LinQ

WPF

網路資源

教學影片

投影片

教學文章

軟體下載

考題解答

101習題

簡介

聊天程式是學習網路程式設計很好的入門題目之一,在本文中,我們將示範如何用 C# 的 Socket 函式庫設計一個網路聊天程式。以下是這個程式的執行時的一個畫面,讀者可以看到我們在兩個命令列視窗中執行同一個 ChatBox 程式,左上角是 Server 程式,右下角是 Client 程式。

ChatBox.jpg

在上圖中,Client 可以傳送訊息給 Server ,而 Server 也可傳送訊息給 Client,由於雙方在這個傳送接收的動作上幾乎是相同的,因此在寫程式時就將這些動作封裝後共用,可以讓程式更為精簡,這就是 P2P 架構的程式。

當然,這個程式也可以放在兩台不同的電腦上執行,其結果將與上述結果類似,只是無法同時在一台電腦上看到輸入與輸出的結果而已。

原始程式碼

以下是上述雙向聊天程式 ChatBox 的原始程式碼,其中的 TcpListener 程式是 Client-Server 雙方所共用的部分,因此獨立出來變成一個類別,並且分別在 Client 與 Server 主程式當中都用 new TcpListener() 的方式呼叫。此時雙方都會建立一個寫入迴圈 (outLoop) 與讀取回圈 (inLoop),寫入迴圈不斷等待鍵盤的輸入,並在有輸入時將訊息傳遞給對方。而讀取回圈則是不斷接收對方所傳來的訊息並顯示在螢幕上。

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

class ChatBox
{
    int port = 20;

    public static void Main(String[] args)
    {
        ChatBox chatBox = new ChatBox();
        if (args.Length == 0)
         chatBox.ServerMain();
        else
         chatBox.ClientMain(args[0]);
    }

    public void ServerMain()
    {
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
        Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        newsock.Bind(ipep);
        newsock.Listen(10);
        Socket client = newsock.Accept();
        new TcpListener(client); // create a new thread and then receive message.
        newsock.Close();
    }

    public void ClientMain(String ip)
    {
        IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port);
        Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        server.Connect(ipep);
        new TcpListener(server);
        server.Shutdown(SocketShutdown.Both);
        server.Close();
    }

}

public class TcpListener
{
    Socket socket;
    Thread inThread, outThread;
    NetworkStream stream;
    StreamReader reader;
    StreamWriter writer;

    public TcpListener(Socket s)
    {
        socket = s;
        stream = new NetworkStream(s);
        reader = new StreamReader(stream);
        writer = new StreamWriter(stream);
        inThread = new Thread(new ThreadStart(inLoop));
        inThread.Start();
        outThread = new Thread(new ThreadStart(outLoop));
        outThread.Start();
        inThread.Join(); // 等待 inThread 執行續完成,才離開此函數。 
        // (注意、按照 inLoop 的邏輯,這個函數永遠不會跳出,因為 inLoop 是個無窮迴圈)。
    } 

    public void inLoop()
    {
        while (true)
        {
         String line = reader.ReadLine();
         Console.WriteLine("收到:" + line);
        }
    }

    public void outLoop()
    {
        while (true)
        {
         String line = Console.ReadLine();
         writer.WriteLine(line);
         writer.Flush();
        }
    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License