发送和接收文件一直挂起

时间:2015-07-12 13:42:58

标签: c# sockets send

我的程序应该能够发送和接收文件,但出于某种原因,每当我点击发送(按钮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();
    }
}

2 个答案:

答案 0 :(得分: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 Web服务
  • Web API

答案 1 :(得分:1)

忽略程序中可能出现的任何逻辑错误,无论何时在客户端处理事务,它都是在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;
}

可能存在更多错误。另一个答案也表明了其他一些问题。