C#中的套接字编程 - 客户端从不连接到服务器

时间:2012-10-18 10:35:06

标签: c# sockets localhost

我不是在寻找一个完整的书面解决方案,我只想知道出了什么问题,因为它是学校作业的一部分。这两个课程都是由老师编写的,所以我假设我的电脑出了问题,但我不知道在哪里看。我搜索了一些其他的解决方案,除了低级别的解决方案之外找不到任何与此不同的解决方案,但我也得到了老师的低级解决方案,但也无效。

服务器:

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位计算机也出现了这个问题。

有人知道问题是什么吗?

1 个答案:

答案 0 :(得分:2)

问题几乎肯定存在于构建服务器时使用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];时,我们会得到一个类似于::1的IP地址,那就是问题。但是,如果我们听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(); }
        }
    }
}