C# - 套接字未接收所有字节

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

最佳答案

UDP 套接字和 TCP 套接字之间有很大的区别。
您正在尝试使用 UDP 会更好,因为该协议(protocol)更面向数据包。这意味着如果服务器发送一定数量的字节,客户端“可能”接收到相同数量的字节或根本什么也接收不到。

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

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

关于C# - 套接字未接收所有字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37626856/

相关文章:

php - 打开多个持久套接字到同一个域?

C编程-tcp套接字远程端口检索

Python ping 脚本在第一次尝试时总是失败

c++ - 客户端-服务器设计

iOS 7 不显示网络事件指示器

c# - 将自定义 EventArgs 作为事件参数传递

c# - 编译器优化在循环期间保持静态的属性

c++ - N*(connect + send + close) vs (Nagle disable + connect + N*send + close),N > 1

c# - Xamarin Forms 访问所有 View 模型

c# - LibGDX/Java 或 XNA/C#