【问题标题】:Sending and receiving files keeps hanging发送和接收文件一直挂起
【发布时间】:2015-09-30 20:00:07
【问题描述】:

我的程序应该能够发送和接收文件,但由于某种原因,每当我单击发送(按钮 1)和接收(按钮 2)按钮时,它一直挂起。不确定我的代码是否有问题?另外,与我在网上找到的其他示例相比,我觉得我的代码相当长,但我不知道如何纠正。

客户代码

    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9000);

    private void Form1_Load(object sender, EventArgs e)
    {
        try
        {
            socket.Connect(remoteEP);
            textBox2.Text = "Connected to Server";
        }
        catch (Exception ex)
        {
            textBox2.Text = "Unable to connect to Server";
            textBox2.Text = ex.Message;
        }
    }

    public const string SEND = "[SEND]";
    public const string RECEIVE = "[RECEIVE]";
    public const string QUIT = "[QUIT]";

    private void button1_Click(object sender, EventArgs e)
    {
        textBox1.Clear();
        textBox2.Clear();
        NetworkStream stream = new NetworkStream(socket);
        StreamReader reader = new StreamReader(stream);
        StreamWriter writer = new StreamWriter(stream);

        try
        {
            writer.WriteLine(RECEIVE);
            writer.Flush();
            writer.WriteLine(textBox1.Text);
            writer.Flush();
            Bitmap bmp = new Bitmap(@"C:\Users\Y400\Desktop\Lectures\Year 3\WAD\Week 11" + textBox1.Text);
            MemoryStream ms = new MemoryStream();
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            byte[] bmpBytes = ms.GetBuffer();
            bmp.Dispose();
            ms.Close();
            int sent;
            sent = sendData(socket, bmpBytes);
            textBox1.Text = "Transferring file complete\r\n";
            textBox1.Text += bmpBytes.Length + " bytes sent to Server.";
        }
        catch (Exception ex)
        {
            textBox2.Text = ex.Message;
        }
    }

    public static int sendData (Socket s, byte[] data)
    {
        int total = 0;
        int size = data.Length;
        int left = size;
        int sent;

        byte[] datasize = new byte[4];
        datasize = BitConverter.GetBytes(size);
        sent = s.Send(datasize);

        while(total<size)
        {
            sent = s.Send(data, total, left, SocketFlags.None);
            total += sent;
            left -= sent;
        }
        return total;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        textBox2.Clear();
        textBox1.Clear();
        byte[] data = new byte[1024];
        string fileN = textBox2.Text.Trim();
        NetworkStream ns = new NetworkStream(socket);
        StreamReader reader = new StreamReader(ns);
        StreamWriter writer = new StreamWriter(ns);
        writer.WriteLine(SEND);
        writer.Flush();
        writer.WriteLine(fileN);
        writer.Flush();
        try
        {
            while (true)
            {
                data = receiveData(socket);
                MemoryStream ms = new MemoryStream(data);
                break;
            }
            textBox2.Text = ("Receiving file from server ...\r\n" + data.Length + " bytes copied");
        }
        catch (Exception ex)
        {
            textBox2.Text = ex.Message;
        }
    }

    public static byte[] receiveData (Socket s)
    {
        int total = 0;
        int recv;
        byte[] datasize = new byte[4];

        recv = s.Receive(datasize, 0, 4, 0);
        int size = BitConverter.ToInt32(datasize, 0);
        int dataleft = size;
        byte[] data = new byte[size];


        while (total < size)
        {
            recv = s.Receive(data, total, dataleft, 0);
            if (recv == 0)
            {
                break;
            }
            total += recv;
            dataleft -= recv;
        }
        return data;
    }

    private void button3_Click(object sender, EventArgs e)
    {
        textBox1.Clear();
        textBox2.Clear();
        textBox2.Text = "Connection closed";
        socket.Shutdown(SocketShutdown.Both);
        socket.Close();
    }

服务器代码

    class Program
    {
    public const string SEND = "[SEND]";
    public const string RECV = "[RECV]";
    public const string QUIT = "[QUIT]";

    static void Main(string[] args)
    {
        runServer();
    }

    static void runServer()
    {
        try
        {
            byte[] data = new byte[1024];
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 9000);
            server.Bind(localEP);
            server.Listen(10);

            Console.WriteLine("Waiting for Client ...");
            Socket client = server.Accept();
            Console.WriteLine("Client connected");

            NetworkStream stream = new NetworkStream(client);
            StreamReader reader = new StreamReader(stream);
            StreamWriter writer = new StreamWriter(stream);

            try
            {
                while(true)
                {
                    string request = reader.ReadLine();
                    string filename = reader.ReadLine();
                    if (request == QUIT)
                    {
                        Console.WriteLine("Client disconnected");
                        break;
                    }
                    else if (request == SEND)
                    {
                        getFileFromClient(filename, client);
                    }
                    else if (request == RECV)
                    {
                        receiveFileFromClient(filename, client);                        
                    }
                }
             }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    public static void getFileFromClient(string filename, Socket client)
    {
        try
        {
            FileStream output = File.OpenWrite(filename);
            Console.WriteLine(filename + " created");
            int count = 0;
            while(true)
            {
                byte[] data = new byte[1024];
                int size = client.Receive(data);
                output.Write(data, 0, size);
                count += size;
                if(size<1024)
                {
                    break;
                }
            }
            output.Close();
            Console.WriteLine(count + " bytes read from client");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    public static void receiveFileFromClient(string filename, Socket client)
    {
        int count = 0;
        FileStream input = File.OpenRead(filename);
        Console.WriteLine("Reading " + filename);
        while(true)
        {
            byte[] data = new byte[1024];
            int bytesRead = input.Read(data, 0, 1024);
            client.Send(data, bytesRead, SocketFlags.None);
            count += bytesRead;

            if(bytesRead < 1024)
            {
                break;
            }
        }
        Console.WriteLine("Transferring file completed\r\n" + count + " bytes sent to Client");
        input.Close();
    }
}

【问题讨论】:

  • 那么,它一直挂在哪里,你用调试器检查过代码吗?

标签: c# sockets send


【解决方案1】:

一般来说

...尝试以不同的方式解决问题。 你不能只是从互联网上复制粘贴的东西,然后寄希望于最好的结果。您需要彻底了解自己在做什么。

关于您的确切问题

看看button2_Click方法。

它包含一个while 循环,显然永远不会结束。

while (true)
{
    data = receiveData(socket);
    MemoryStream ms = new MemoryStream(data);
    break;
}

由于break 命令,它确实完成了。但这一切都很难阅读。

当您复制粘贴代码然后应用快速修复时,您最终会得到一堆很难调试的代码。

我花了大约 10 分钟才注意到客户端这样定义它的“消息动词”这一事实:

public const string SEND = "[SEND]";
public const string RECEIVE = "[RECEIVE]";
public const string QUIT = "[QUIT]";

而服务器是这样定义它们的:

public const string SEND = "[SEND]";
public const string RECV = "[RECV]";
public const string QUIT = "[QUIT]";

这可能不是唯一的问题,但足以造成死锁, 因为服务器从不执行这个if语句的正分支:

else if (request == RECV)
{
    receiveFileFromClient(filename, client);                        
}

所以客户端相信它即将收到东西,这被证明是错误的。

还要确保在应该发送“SEND”和“RECEIVE”消息动词时不要混淆它们。

祝你好运!

PS:我建议你看看更简单的使用技术来发送和接收数据,例如:

  • WCF
  • ASP.NET 网络服务
  • 网络 API

【讨论】:

  • 支持发现部分问题 ;-) 还有更多问题!!
【解决方案2】:

忽略您的程序中可能发生的任何逻辑错误,您在客户端执行操作时处理事情的方式是在 GUI 线程上执行的操作。这将使您的应用程序看起来像是在锁定,但实际上它是在 GUI 线程上执行您的逻辑。

服务器上也出现了同样的问题。它接受一个连接,然后继续接收文件。在完成接收文件之前,它将无法接收任何其他连接。

服务器也不是没有问题,因为它从不检查它是否从套接字接收到 0 字节。这意味着客户端关闭了它的连接端。您只是假设如果您收到少于 1024 的信息,您将收到文件的最后一部分。对于 TCP,这根本不是真的。如果您收到 0 个字节,您只知道您收到了最后一部分。 TCP 是一种字节流协议,您不能假设您将接收 1024 字节的块。实际上很可能是这种情况,但您不应该这样编码。检查是否接收到 0 字节。在客户端上你确实检查了 0 字节,我很困惑为什么你没有在服务器上做同样的事情。有问题的部分是:

byte[] data = new byte[1024];
int size = client.Receive(data);
output.Write(data, 0, size);
count += size;
if(size<1024) //you can only break if the size is 0
{
     break;
}

可能还有更多错误。由于另一个答案也表明了其他一些问题。

【讨论】:

  • Upvote :) 不幸的是,我们都没有帮助。 @eyeballs 你知道字节流是什么吗?或者更重要的是它不是什么?它不是消息流,这是一个重要的事实。这意味着虽然一方可以向对方发送 3 条“消息”,但后者很可能会收到一条“大消息”或 6 条“小消息”。无论哪种方式,收到“长度为 0 的消息”意味着对方挂断了电话。我说的是我们人类对正在发送的信息的看法。收到它们的方式之所以奇怪,只是因为......
  • @eyeballs .. 它们对于 TCP 不存在。 TCP 仅保证任何“发送”手势的复合字节将以完全相同的顺序传递给对方。它没有说明什么时候会这样做,但我们都同意这是尽快的。它没有说明任何关于边界的内容。此“发送手势”的最后一个字节可以与下一个“发送手势”的第一个字节一起接收。
猜你喜欢
  • 2013-11-18
  • 2012-08-10
  • 1970-01-01
  • 2016-07-23
  • 2014-03-16
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多