C# - 套接字没有接收到所有字节

时间:2016-06-04 05:51:31

标签: c# sockets networking tcp serversocket

我一直在努力解决我的错误。我的客户端/服务器在同一台机器上似乎工作正常。当代码在不同的PC上执行时,由于某种原因,只有部分字节到达服务器。我似乎无法获得字节来解释我尝试了多少。似乎截止点是367字节,它不再需要传输。如果有人知道我做错了什么,我们将非常感谢解决方案。

提前致谢!

服务器:

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;
            }
        }
    }

3 个答案:

答案 0 :(得分:1)

正如您在代码中提到的,可能会有更多数据,因此您存储到目前为止收到的数据。但是你没有让代码得到剩下的数据。

MSDN有一个如何正确执行此操作的示例:

https://msdn.microsoft.com/en-us/library/bew39x2a.aspx?f=255&MSPPError=-2147217396

答案 1 :(得分:1)

UDP套接字和TCP套接字之间存在很大差异。 您正在尝试使用UDP可以更好地工作,因为此协议更加面向数据包。这意味着,如果服务器发送一定数量的字节,则客户端可能会'接收相同的特定字节数或根本不接收任何字节。

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

到目前为止你得到的建议是正确的,你必须继续打电话给接收。直到没有什么东西可以接受了。你怎么知道没有什么东西可以收到了?通常通过在0长度的接收中接收TCP消息来检测。这意味着对等体已关闭其套接字的末尾,不再发送。这反过来意味着您可以关闭套接字的末尾。

答案 2 :(得分:0)

这是设计的。这是开发人员在套接字方面犯的一个常见错误。

要正确接收数据,您需要在循环中继续接收数据,直到收到所需的字节数。继续附加到接收缓冲区,直到获得所需的字节数。

某些套接字实现具有"等待所有"的概念。标志(例如MSG_WAITALL),但如果远程在发送后关闭了连接,即使这将返回部分数据。

防守代码。代码就像发送方一次只发送1个字节一样。你将处于良好的状态。