1

我对 C# 和客户端-服务器编程都是新手。现在,对于课堂,我正在尝试在不使用任何预先建立的 FTP 库的情况下创建一个 FTP 客户端。我觉得我的项目大部分都已关闭,但是当我进行多个需要使用数据端口(list、retr 等)的调用时,我遇到了问题。这是代码示例这是打破:

writer.WriteLine(portcmd);
writer.Flush();

GetServerMessage(stream);

writer.WriteLine("list ");
writer.Flush();


tmpserver = new TcpListener(IPAddress.Any, 3128);
tmpserver.Start(); 
tmpclient = tmpserver.AcceptTcpClient();
Console.WriteLine("gothere");

if (!tmpclient.Connected)
{
    tmpserver.Start();
}

StreamReader tmpreader = new StreamReader(tmpclient.GetStream());

GetServerMessage(stream);
while (tmpreader.Peek() != -1)
{
    Console.WriteLine(tmpreader.ReadLine());
}

tmpclient.Close();
tmpserver.Stop();

GetServerMessage(stream);

Getservermessage 是一种获取网络流并在 0.5 秒超时内打印出所有可用内容的方法,stream 是当前连接到 FTP 服务器的 NetworkStream,而 writer 是包装在 StreamReader 中以便于编写 ASCII 的同一网络流字符到服务器。如果您想知道为什么我使用流读取器从数据连接中读取数据,那是因为服务器在传输数据后关闭了连接,因此我可以轻松获得 eof 通知。当我使用封闭的网络流时,我的 GetServerMessage 方法由于某种原因而中断。

此代码将端口命令发送到 FTP 服务器以通知它我将需要数据连接(前 2 行)然后发送列表命令,建立与服务器的数据连接,获取所需信息,然后终止数据连接(代码的其余部分)。

此代码在我第一次运行时将毫无缺陷地执行,但如果我再试一次,它会挂在“tmpclient = tmpserver.AcceptTcpClient();”上 线。它永远不会到达“gothere”打印语句。我相信这是因为我在同一端口上从同一台机器接收客户端,但我不确定。我尝试添加一个布尔值以确保 AcceptTcpClient() 仅运行一次,但随后出现运行时错误,Visual Studio 告诉我我可能已经“在完成资源之前释放了资源”我预测这将是一个问题,但是如何判断服务器是否在关闭一次后重新建立连接?

在给定代码的末尾,我停止 tmpserver 并关闭 tmpclient。我最初这样做是因为我知道 FTP 服务器在完成传输后会关闭连接,并认为这是正确的做法。我发现如果我注释掉这些行,代码将执行多次,但流似乎是空的......我不确定这些信息是否有帮助,但我想我会提到它。

如果我不清楚,我深表歉意,但我对这个主题缺乏了解,这使得我很难表达我的问题。如果对问题所在有任何困惑,我很乐意尝试解决它。

4

3 回答 3

3

为了能够接受另一个客户,您应该执行tmpclient = tmpserver.AcceptTcpClient();并等待第一个客户完成其工作(在接受第二个客户之前)可能不是一个好主意

这是一个示例服务器代码,它等待连接并回显每个客户端发送的字符串。你可以用telnet localhost 3128

Thread t = new Thread(Server);
t.IsBackground = true;
t.Start();

-

void Server()
{
    TcpListener listener = new TcpListener(IPAddress.Any, 3128);
    listener.Start();
    while (true)
    {
        var client = listener.AcceptTcpClient();
        new Thread(() =>
        {
            using (client)
            {
                var reader = new StreamReader(client.GetStream());
                var writer = new StreamWriter(client.GetStream());
                while (true)
                {
                    string line = reader.ReadLine();
                    if (line == "QUIT") break;
                    writer.WriteLine("From Thread[" + Thread.CurrentThread.ManagedThreadId + "] > " + line);
                    writer.Flush();
                }
            }
        }).Start();
    }
}
于 2012-04-24T21:34:43.807 回答
0

好的,是这样的。要以简单的方式创建服务器,您需要线程化处理客户端套接字的代码。当接受返回时,创建并启动一个线程,将“tmpclient”传递给它,然后再次循环到接受调用,以便任何新客户端都可以连接。在新生成的 server<> 客户端线程中,循环读取和写入传递的套接字以与客户端通信。

于 2012-04-24T21:13:26.267 回答
0

关闭 tcp 客户端流后,您将无法再从从中提取的流中读取数据。

var stream = tcpClient.GetStream();
...
tcpclient.Close();
...
stream.Read .. fail

客户端将不得不请求另一个连接,

或者

您应该保持您的 tcp 客户端套接字打开。

更复杂的服务器将保留一些关于客户端的元数据(状态)缓存,因此当套接字意外关闭时 - 并且客户端快速尝试重新连接,服务器可以继续顺利处理。

于 2012-04-24T21:13:48.790 回答