2

コンソールに必要最小限のチャット クライアントがあります。これがコードです

サーバー用

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

namespace chat_server
{
 class Program
{
    static TcpListener server = new TcpListener(IPAddress.Any, 9999);

    static void input(object obs)
    {
        StreamWriter writer = obs as StreamWriter;
        string op = "nothing";
        while (!op.Equals("exit"))
        {
            Console.ResetColor();
            Console.WriteLine("This is the " + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Enter your text(type exit to quit)");
            op = Console.ReadLine();
            writer.WriteLine(op);
            writer.Flush();
        }
    }

    static void output(Object obs)
    {
        StreamReader reader = obs as StreamReader;
        Console.ForegroundColor = ConsoleColor.Green;
        while (true)
        {
            Console.WriteLine(reader.ReadLine());
        }
    }

    static void monitor()
    {
        while (true)
        {
            TcpClient cls = server.AcceptTcpClient();
            Thread th = new Thread(new ParameterizedThreadStart(mul_stream));
            th.Start(cls);
        }
    }

    static void mul_stream(Object ob)
    {
        TcpClient client = ob as TcpClient;
        Stream streams = client.GetStream();
        StreamReader reads = new StreamReader(streams);
        StreamWriter writs = new StreamWriter(streams);

        new Thread(new ParameterizedThreadStart(output)).Start(reads);
        input(writs);
    }

    static void Main(string[] args)
    {

        server.Start();
        monitor();
        server.Stop();
        Console.ReadKey();
    }
 }
}

ここにクライアントコードがあります

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

namespace chat_client
{
 class Program
 {
    static StreamReader reader;
    static StreamWriter writer;
    static Thread input_thread;

    static void input()
    {
        string op = "nothing";
        while (!op.Equals("exit"))
        {
            Console.ResetColor();
            Console.WriteLine("Enter your text(type exit to quit)");
            op = Console.ReadLine();
            writer.WriteLine(op);
            writer.Flush();
        }
    }

    static void output()
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        while (true)
        {
            Console.WriteLine(reader.ReadLine());
        }
    }


    static void Main(string[] args)
    {
        Console.WriteLine("Enter the ip address");
        string ip = Console.ReadLine();
        TcpClient client = new TcpClient(ip,9999);

        NetworkStream stream = client.GetStream();
        reader = new StreamReader(stream);
        writer = new StreamWriter(stream);

        input_thread = new Thread(input);
        input_thread.Start();

        /*
        writer.Write("Hello world");
        writer.Flush();
        Console.WriteLine("Message Sent");*/
        output();
        client.Close();
        Console.ReadKey();
    }
 }
}

問題は、このコードを GUI に変換する際に問題が発生していることです。たとえば、特定のストリームを介してクライアントにメッセージを配信するサーバーの入力機能は、GUI の [送信] ボタンとある程度同等である必要があります。

ただし、各スレッドは独自のストリームを作成するため、異なるスレッドで個別のイベント ハンドラーを作成することは良い考えではないと思います。

要するに、このプロジェクトをどこから始めるべきかについてアドバイスが必要です。

ありがとうございました。

4

1 に答える 1

1

ネットワーキングは難しい。すべてを読み取り、すべてを完全なメッセージとして扱う現在のアプローチは脆弱です。デバッグ中は機能しますが、TCP はストリーム ベースであるため、本番環境では失敗します。

代わりに、既存のフレームワークを使用して、ネットワーク レイヤーを抽象化することができます。たまたま、オープン ソース (LGPL) であるフレームワークを作成しました。

この場合、チャットできるようにしたいだけです。そこで、次のようなチャット メッセージ定義を追加しました。

public class ChatMessage
{
    public DateTime CreatedAt { get; set; }
    public string UserName { get; set; }
    public string Message { get; set; }
}

そのメッセージは共有アセンブリに入れられます (クライアントとサーバーの両方で使用されます)。

サーバー自体は次のように定義されています。

public class ChatServer : IServiceFactory
{
    private readonly List<ClientChatConnection> _connectedClients = new List<ClientChatConnection>();
    private readonly MessagingServer _server;


    public ChatServer()
    {
        var messageFactory = new BasicMessageFactory();
        var configuration = new MessagingServerConfiguration(messageFactory);
        _server = new MessagingServer(this, configuration);
    }

    public IServerService CreateClient(EndPoint remoteEndPoint)
    {
        var client = new ClientChatConnection(this);
        client.Disconnected += OnClientDisconnect;

        lock (_connectedClients)
            _connectedClients.Add(client);

        return client;
    }

    private void OnClientDisconnect(object sender, EventArgs e)
    {
        var me = (ClientChatConnection) sender;
        me.Disconnected -= OnClientDisconnect;
        lock (_connectedClients)
            _connectedClients.Remove(me);
    }

    public void SendToAllButMe(ClientChatConnection me, ChatMessage message)
    {
        lock (_connectedClients)
        {
            foreach (var client in _connectedClients)
            {
                if (client == me)
                    continue;

                client.Send(message);
            }
        }
    }

    public void SendToAll(ChatMessage message)
    {
        lock (_connectedClients)
        {
            foreach (var client in _connectedClients)
            {
                client.Send(message);
            }
        }
    }

    public void Start()
    {
        _server.Start(new IPEndPoint(IPAddress.Any, 7652));
    }
}

見る?ネットワークコードはどこにもありません。

クライアントはイベントが簡単です:

static class Program
{
    private static MainForm _mainForm;
    private static MessagingClient _client;

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        ConfigureChat();
        _mainForm = new MainForm();
        Application.Run(_mainForm);
    }

    private static void ConfigureChat()
    {
        _client = new MessagingClient(new BasicMessageFactory());
        _client.Connect(new IPEndPoint(IPAddress.Loopback, 7652));
        _client.Received += OnChatMessage;
    }

    private static void OnChatMessage(object sender, ReceivedMessageEventArgs e)
    {
        _mainForm.InvokeIfRequired(() => _mainForm.AddChatMessage((ChatMessage)e.Message));
    }

    public static void SendChatMessage(ChatMessage msg)
    {
        if (msg == null) throw new ArgumentNullException("msg");
        _client.Send(msg);
    }
}

ここに画像の説明を入力

完全な例は、https ://github.com/jgauffin/Samples/tree/master/Griffin.Networking/ChatServerClient で入手できます。

アップデート:

これは学校のプロジェクトであり、.NET 以外は使用できないため、おそらく最も簡単な方法を使用します。そしてそれは改行 ( "\r\n") を区切り文字として使用することです。

だからあなたが今使ったそれぞれの側var chatMessage = streamReader.ReadLine()streamWriter.WriteLine("Chat message");

于 2012-11-18T15:19:56.160 に答える