【问题标题】:Socket Programming in C# - The Client Never Connects to the ServerC# 中的套接字编程 - 客户端从不连接到服务器
【发布时间】:2012-10-08 19:04:31
【问题描述】:

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

服务器:

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 位计算机上。

有人知道问题出在哪里吗?

【问题讨论】:

  • 您是否尝试将 2 个程序(服务器和客户端)彼此分开,这会带来什么?如果允许连接到该特定端口,还要检查您 PC 的防火墙?如果这不是问题,您还可以使用以下cmd 命令检查您的服务器应用程序是否真的正确启动:netstat -a 并检查服务器端口是否在那里侦听。
  • TCP 127.0.0.1:2104 PC_NAME 监听。 2104 是我要监听的端口,因此可以正常工作。我现在试着把它们分开。
  • 两个单独的程序不能正常工作,它们会给出完全相同的问题。

标签: c# sockets localhost


【解决方案1】:

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

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

接下来,尽管我确信您正在这样做,但请确保 clientPortserverPort 的端口相同。

接下来,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.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(); }
        }
    }
}

【讨论】:

  • Dns.Resolve 是Obsolute,所以我在Dns.GetHostEntry 中更改了它,但并没有解决问题。我真的很确定正确的端口:我打印它们并与另一个控制台上的端口对应。由于程序甚至没有到达 while(true) 循环,所以我暂时不会更改它。
  • @Caution,我已经为你工作了。您应该能够查看我的代码并从您的原始示例中学到一些新东西。
  • 谢谢,这解决了我的部分问题。我还发现了另一部分:我在同一个端口上启动了多个服务器套接字,因为我没想过每个端口只做一个服务器。但这不是这个问题的一部分:这是我可以在没有任何帮助的情况下解决的问题。
  • @Caution,很高兴能为您提供帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
  • 1970-01-01
  • 2016-02-09
  • 1970-01-01
  • 2017-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多