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 中的 SEND 按钮。

然而,每个线程都会创建自己的流,我认为在不同的线程上创建单独的事件处理程序不是一个好主意。

简而言之,我需要一些关于从哪里开始这个项目的建议。

谢谢你。

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 回答