2

我不是在寻找完整的书面解决方案,我只想知道出了什么问题,因为它是学校作业的一部分。这两节课都是老师写的,所以我认为我的电脑出了点问题,但我不知道去哪里找。我搜索了一些其他解决方案,除了低级解决方案外,找不到任何与此不同的解决方案,但我也从我的老师那里得到了一个低级解决方案,但这也不起作用。

服务器:

var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddress, clientPort);
server.Start();
TcpClient client = server.AcceptTcpClient(); // The server gets here
StreamReader clientIn = new StreamReader(client.GetStream());
StreamWriter clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
while (true)
{
    string msg = clientIn.ReadLine();
    Console.WriteLine(msg);
    clientOut.WriteLine(msg);  
}

客户端:

TcpClient client = new TcpClient("localhost", serverPort); //The client gets here
StreamReader clientIn = new StreamReader(client.GetStream());
StreamWriter clientOut = new StreamWriter(client.GetStream());

clientOut.AutoFlush = true;

while (true)
{
    clientOut.WriteLine(Console.ReadLine());
    Console.WriteLine(clientIn.ReadLine());
}

由于客户端处于 try-catch 块中,该块处于循环中,直到他获得连接,所以他多次尝试连接到服务器。服务器没有被捕获,因为 AcceptTcpClient 只是等待连接,但是当它们在同一个 ip 和另一个进程的端口上时,它们永远不会达到任何连接。

连接是在单独的线程中启动的,但主线程似乎要等到一个完成,这不是我所期望的。我试图让他们都睡在各种方法上(使用Thread.Sleep(1000)Thread.Sleep(0)(文档说如果你这样做,将安排另一个线程)和while(stopwatch<1000ms) {for(i<100000)}),它们都没有帮助。主线程只有在连接线程的睡眠消失并且连接线程再次创建客户端的那一刻才有了一些进展。

该问题也出现在另一台 W7 64 位计算机上。

有谁知道问题是什么?

4

1 回答 1

4

几乎可以肯定,问题在于您IPAddress.Any在构建服务器时使用的事实。这是一个问题的原因是因为这不一定会解决localhost,尽管你可能很幸运,但它并不一致。因此,我建议使用如下 IP 地址启动服务器:

var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddress, clientPort);

接下来,尽管我确信您正在执行此操作,但请确保 和 的端口clientPort相同serverPort

接下来,while (true)循环对我来说非常可疑,因此在下面的示例中,我将对其进行更改。除非不可能总是避免while (true),否则你实际上是在乞求一个问题。

最后,围绕你将如何在这里进行线程化,你将需要以某种方式构建两个单独的线程,我将推荐该BackgroundWorker课程(其他人可能会推荐async-await,但我对它的了解还不够,无法推荐你将需要使用 .NET 4.5,我不知道你是不是)。

所以,你可以BackgroundWorker为服务器构建一个这样的(你可以为客户端构建另一个类似的):

var worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;

worker.ProgressChanged += (s, args) =>
{
    Console.WriteLine(args.UserState);
}

worker.DoWork += (s, args) =>
{
    // startup the server on localhost
    var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
    TcpListener server = new TcpListener(ipAddress, clientPort);
    server.Start();

    while (!worker.CancellationPending)
    {
        // as long as we're not pending a cancellation, let's keep accepting requests
        TcpClient client = server.AcceptTcpClient();

        StreamReader clientIn = new StreamReader(client.GetStream());
        StreamWriter clientOut = new StreamWriter(client.GetStream());
        clientOut.AutoFlush = true;

        while ((string msg = clientIn.ReadLine()) != null)
        {
            worker.ReportProgress(1, msg);  // this will fire the ProgressChanged event
            clientOut.WriteLine(msg);
        }
    }
}

最后,在某个地方你需要通过RunWorkerAsync这样的调用来启动这些worker:

worker.RunWorkerAsync();

更新

好的,下面是连接到 2104 的完全正常工作的控制台应用程序。您需要注意的一件事是,使用时var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];我们得到的 IP 地址看起来像这样::1,这就是问题所在。但是,如果我们在127.0.0.1:2104客户端上侦听,则可以连接,因为它在发出时尝试连接的内容var result = client.BeginConnect("localhost", 2104, null, null);,这与发出相同new TcpClient("localhost", 2104);

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

namespace ConsoleApplication13
{
    class Program
    {
        static void Main()
        {
            var worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;

            worker.ProgressChanged += (s, args) =>
            {
                Console.WriteLine(args.UserState);
            };

            worker.DoWork += (s, args) =>
            {
                // startup the server on localhost 
                var ipAddress = IPAddress.Parse("127.0.0.1");
                TcpListener server = new TcpListener(ipAddress, 2104);
                server.Start();

                while (!worker.CancellationPending)
                {
                    Console.WriteLine("The server is waiting on {0}:2104...", ipAddress.ToString());

                    // as long as we're not pending a cancellation, let's keep accepting requests 
                    TcpClient attachedClient = server.AcceptTcpClient();

                    StreamReader clientIn = new StreamReader(attachedClient.GetStream());
                    StreamWriter clientOut = new StreamWriter(attachedClient.GetStream());
                    clientOut.AutoFlush = true;

                    string msg;
                    while ((msg = clientIn.ReadLine()) != null)
                    {
                        Console.WriteLine("The server received: {0}", msg);
                        clientOut.WriteLine(string.Format("The server replied with: {0}", msg));
                    }
                }
            };

            worker.RunWorkerAsync();

            Console.WriteLine("Attempting to establish a connection to the server...");

            TcpClient client = new TcpClient();

            for (int i = 0; i < 3; i++)
            {
                var result = client.BeginConnect("localhost", 2104, null, null);

                // give the client 5 seconds to connect
                result.AsyncWaitHandle.WaitOne(5000);

                if (!client.Connected)
                {
                    try { client.EndConnect(result); }
                    catch (SocketException) { }

                    string message = "There was an error connecting to the server ... {0}";

                    if (i == 2) { Console.WriteLine(message, "aborting"); }
                    else { Console.WriteLine(message, "retrying"); }

                    continue;
                }

                break;
            }

            if (client.Connected)
            {
                Console.WriteLine("The client is connected to the server...");

                StreamReader clientIn = new StreamReader(client.GetStream());
                StreamWriter clientOut = new StreamWriter(client.GetStream());

                clientOut.AutoFlush = true;

                string key;
                while ((key = Console.ReadLine()) != string.Empty)
                {
                    clientOut.WriteLine(key);
                    Console.WriteLine(clientIn.ReadLine());
                }
            }
            else { Console.ReadKey(); }
        }
    }
}
于 2012-10-18T11:31:09.913 回答