C# - 套接字未接收到所有字节 [英] C# - Sockets not receiving all bytes

查看:34
本文介绍了C# - 套接字未接收到所有字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力改正我的错误.我的客户端/服务器在同一台机器上似乎工作正常.当代码在不同的 PC 上执行时,由于某种原因,只有部分字节到达服务器.无论我尝试了多少,我似乎都无法获得字节.看起来截止点是 367 字节,它不想再传输了.如果有人知道我做错了什么,将不胜感激.

I have been struggling to fix my mistake. My client/server seems to work fine when on the same machine. When the code is executed on a different PC, for some reason only part of the bytes are reaching the server. I cannot seem to get the bytes to go through to matter how much I try. It seems the cutoff point is 367 bytes and it does not want to transfer anymore. If anyone knows what I am doing wrong, a solution would be much appreciated.

提前致谢!

服务器:

using System;
using System.Data.SQLite;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;

namespace DMAssist
{

    // State object for reading client data asynchronously
    public class StateObject
    {
        // Client  socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1024;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
        // Current URL string
    }

    public class asyncserver
    {

        public asyncserver()
        {
        }

        // Thread signal.
        public static ManualResetEvent allDone = new ManualResetEvent(false);

        public static string GetLocalIPAddress()
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    return ip.ToString();
                }
            }
            throw new Exception("Local IP Address Not Found!");
        }

        public void StartListening()
        {
            // Data buffer for incoming data.
            byte[] bytes = new Byte[1024];

            // Establish the local endpoint for the socket.
            // The DNS name of the computer
            // running the listener is "host.contoso.com".
            IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 25599);

            // Create a TCP/IP socket.
            Socket listener = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen for incoming connections.
            try
            {
                listener.Bind(localEndPoint);
                listener.Listen(100);

                while (true)
                {
                    // Set the event to nonsignaled state.
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections.
                    Console.WriteLine("Waiting for a connection...");
                    listener.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        listener);

                    // Wait until a connection is made before continuing.
                    allDone.WaitOne();
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.WriteLine("\nPress ENTER to continue...");
            Console.Read();

        }

        public void AcceptCallback(IAsyncResult ar)
        {
            // Signal the main thread to continue.
            allDone.Set();

            // Get the socket that handles the client request.
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);

            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = handler;
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
        }


        public byte[] ObjectToByteArray(object obj)
        {
            if (obj == null)
                return null;

            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, obj);
            return ms.ToArray();
        }

        private Object ByteArrayToObject(byte[] arrBytes)
        {
            MemoryStream memStream = new MemoryStream();
            BinaryFormatter binForm = new BinaryFormatter();
            memStream.Write(arrBytes, 0, arrBytes.Length);
            memStream.Seek(0, SeekOrigin.Begin);
            Object obj = (Object)binForm.Deserialize(memStream);
            return obj;
        }


        public void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;
            String connectedAddress = String.Empty;
            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;
            IPEndPoint remoteIpEndPoint = handler.RemoteEndPoint as IPEndPoint;
            connectedAddress = remoteIpEndPoint.Address.ToString();

            // Read data from the client socket. 
            int bytesRead = handler.EndReceive(ar);

            if (bytesRead > 0)
            {

                Console.WriteLine("Bytes read: " + bytesRead);

                // There  might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(
                    state.buffer, 0, bytesRead));

                object rawbytes = ByteArrayToObject(state.buffer);
                netObject recvobject = (netObject)rawbytes;

                Send(handler, (object)recvobject);
            }
   }

        private void Send(Socket handler, object data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = ObjectToByteArray(data);

            // Begin sending the data to the remote device.
            handler.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback(SendCallback), handler);
        }

        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket handler = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to client.", bytesSent);

                handler.Shutdown(SocketShutdown.Both);
                handler.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}

客户:

 using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.IO;
    using System.Collections;

    namespace DMAssist
    {
        public class asyncsclient {

            public asyncsclient()
            {
            }

            public byte[] ObjectToByteArray(object obj)
            {
                if (obj == null)
                    return null;

                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                bf.Serialize(ms, obj);
                return ms.ToArray();
            }

            private Object ByteArrayToObject(byte[] arrBytes)
            {
                MemoryStream memStream = new MemoryStream();
                BinaryFormatter binForm = new BinaryFormatter();
                memStream.Write(arrBytes, 0, arrBytes.Length);
                memStream.Seek(0, SeekOrigin.Begin);
                Object obj = (Object)binForm.Deserialize(memStream);
                return obj;
            }

            static byte[] GetBytes(string str)
            {
                byte[] bytes = new byte[str.Length * sizeof(char)];
                System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
                return bytes;
            }

            static string GetString(byte[] bytes)
            {
                char[] chars = new char[bytes.Length / sizeof(char)];
                System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
                return new string(chars);
            }

            public object sendObject(object outgoingObject, bool expectRecieve)
            {
                try
                {

                    Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    IPAddress ip = IPAddress.Parse("x.x.x.x");
                    IPEndPoint remoteEP = new IPEndPoint(ip, 25599);
                    soc.Connect(remoteEP);

                    byte[] byData = ObjectToByteArray(outgoingObject);

                    //Console.WriteLine("Array length:" + byData.Length);

                    soc.Send(byData);


                    if (expectRecieve)
                    {
                        byte[] buffer = new byte[1024];
                        int iRx = soc.Receive(buffer);

                        object rawbytes = ByteArrayToObject(buffer);
                        netObject recvobject = (netObject)rawbytes;

                        Console.WriteLine("Writing stopped");
                        soc.Close();
                        soc.Dispose();

                        return recvobject;
                    }
                    else
                    {
                        soc.Close();
                        soc.Dispose();

                        return "";
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("Server unreachable. Make sure server is broadcasting on port 25599 successfully.", "DMAssist Error 0xC1");
                }
                return null;
            }
        }
    }

推荐答案

UDP 套接字和 TCP 套接字之间存在很大差异.您尝试使用 UDP 会更好,因为该协议更面向数据包.这意味着如果服务器发送了一定数量的字节,客户端可能"接收到相同数量的字节或什么也没有收到.

There is a big difference between UDP sockets and TCP sockets. What you are trying would work better with UDP because this protocol is more packet oriented. This means that if a server sends a certain number of bytes, the client 'might' receive the same certain number of bytes or receive nothing at all.

对于 TCP,它是不同的,因为它是一种流协议,这意味着字节只是按服务器认为合适的方式顺序发送.通常它会尝试填满 mtu,当您收到时,您很可能会收到您必须自己附加的多个块中的数据.TCP 也是面向连接且可靠的.字节从客户端被确认到服务器,反之亦然,如果没有及时收到确认,则重新传输.这意味着即使是 TCP 级别的数据包也可能被乱序接收.TCP 会将它们组合在一起.您在应用程序级别将按顺序收到所有内容.

For TCP it is different because it is a streaming protocol which means bytes are just sent sequentially anyway the server sees fit. Usually it will try to fill up to the mtu and when you receive you will very likely receive the data in multiple chunks that you have to append yourself. TCP is a also connection oriented and reliable. Bytes are acked from the client to the server and vice versa, and retransmitted if an ack is not received in due time. This means even that packets can at the TCP level be received out of order. TCP will fit them together. You at the application level will receive everything in order.

到目前为止你得到的建议是正确的,你必须继续调用接收.直到没有任何东西可以接收为止.你怎么知道没有什么可以接收了?通常通过在接收中接收长度为 0 的 TCP 消息来检测.这意味着对等方已经关闭了它的套接字端并且不会再发送.这反过来意味着您可以关闭套接字的一端.

The advice you got so far is correct, you have to keep calling receive. And this until there is nothing to receive anymore. And how do you know that there is nothing to receive anymore ? Usually that is detected by receiving a TCP message in receive with 0 length. This means that the peer has closed its end of the socket and will not send anymore. This in turn means that you can close your end of the socket.

这篇关于C# - 套接字未接收到所有字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆