繁体   English   中英

网络套接字-仅第一条消息总是会完成

[英]Network Socket - just the first message always completes

我在客户端套接字(同步)/服务器套接字(异步)环境中遇到以下问题。 如果我从客户端向服务器发送了多个消息,则第一个消息将毫无问题地完成,并且将被客户端毫无问题地接收。 当我发送第二条消息时,只有几个字节经过。 这似乎不是客户端的问题,因为它看起来客户端一直在发送整个消息。 疯狂的事情是,如果我完全停止了客户机上的项目,然后重新开始,那么即使服务器组件一直运行,第一条消息也会再次完成。

我想做什么...基本上,我想通过网络传输不同的对象(大多数xml结构化)并在客户端上接收它。 因此,我进行序列化/反序列化。 以下代码的基础是扩展的msdn示例。

//客户:

class ProgramClient
{
    static void Main(string[] args)
    {
        string rootNode = "config";

        StreamReader configStream = new StreamReader(config);

        XmlDocument xml = new XmlDocument();
        xml.Load(configStream);

        SynchronousSocketClient socket = new SynchronousSocketClient("192.168.0.1", 40001, "c:\\log", xml);
        socket.StartClient();
        socket.Dispose();
        socket = new SynchronousSocketClient("192.168.0.1", 40001, "c:\\log", xml);
        socket.StartClient();
        socket.Dispose();
    }
}


class SynchronousSocketClient : IDisposable
{
    private string ip;
    private int port;
    private object data;
    public StreamWriter log;

    public event EventHandler Disposed;

    public SynchronousSocketClient(string ip, int port, string logfile, object data)
    {
        this.ip = ip;
        this.port = port;
        this.data = data;
        openLog(logfile);
    }

    public void openLog(string logfile)
    {
        log = new StreamWriter(logfile, true);
    }

    public void Dispose()
    {
        log.Close();
        if (this.Disposed != null)
            this.Disposed(this, EventArgs.Empty);
    }

    // Convert an object to a byte array
    private byte[] Serialize(object obj)
    {
        Stream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(stream, obj);
        byte[] b = null;
        b = new byte[stream.Length];
        stream.Position = 0;
        stream.Read(b, 0, (int)stream.Length);
        stream.Close();
        return b;
    }

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

    // Connect to a remote device.
    try {
        // Establish the remote endpoint for the socket.
        // This example uses port 11000 on the local computer.
        IPHostEntry ipHostInfo = Dns.GetHostEntry(ip);
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint remoteEP = new IPEndPoint(ipAddress,port);

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

        // Connect the socket to the remote endpoint. Catch any errors.
        try {
            sender.Connect(remoteEP);

            log.WriteLine(DateTime.Now+": Socket connected to {0}",
                sender.RemoteEndPoint.ToString());

            // Encode the data string into a byte array.
            byte[] msg = Serialize(data);

            // Send the data through the socket.
            int bytesSent = sender.Send(msg);

            // Receive the response from the remote device.
            int bytesRec = sender.Receive(bytes);
            log.WriteLine(DateTime.Now + ": {0}",
                Encoding.Unicode.GetString(bytes,0,bytesRec));

            // Release the socket.
            sender.Shutdown(SocketShutdown.Both);
            sender.Close();

        } catch (ArgumentNullException ane) {
            log.WriteLine(DateTime.Now + ": ArgumentNullException : {0}", ane.ToString());
        } catch (SocketException se) {
            log.WriteLine(DateTime.Now + ": SocketException : {0}", se.ToString());
        } catch (Exception e) {
            log.WriteLine(DateTime.Now + ": Unexpected exception : {0}", e.ToString());
        }

    } catch (Exception e) {
        log.WriteLine(DateTime.Now+": "+e.ToString());
    }

    }
}

//服务器:

class ProgramServer
{
    static void Main(string[] args)
    {
        NetworkSocket socket = new NetworkSocket(nwsocketport);
        socket.Start();
    }
}



public class StateObject
{
    // Client socket.
    public Socket workSocket = null;
    // Size of send buffer.
    public const int sBufferSize = 1024;
    // send buffer.
    public byte[] sBuffer = new byte[sBufferSize];
    // Received data object;
    public object data = null;
    // bytes read so far
    public int bytesRead;
    //receive buffer
    public byte[] rBuffer;
}

public class NetworkSocket
{
    private int port;
    Socket listener;

    IPEndPoint localEndPoint;


    public NetworkSocket(int port) {
        this.port = port;
    }

    public void Start() {
        // Establish the local endpoint for the socket.
        IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[1];
        localEndPoint = new IPEndPoint(ipAddress, port);

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

        //set socket timeouts
        listener.SendTimeout = 5000;
        listener.ReceiveTimeout = 5000;

        // Bind the socket to the local endpoint and listen for incoming connections.
        try {
            listener.Bind(localEndPoint);
            listener.Listen(1);
            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

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

    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();

        // Data buffer for incoming data.
        state.rBuffer = new Byte[listener.ReceiveBufferSize];

        state.workSocket = handler;
        handler.BeginReceive(state.rBuffer, 0, state.rBuffer.Length, 0,
            new AsyncCallback(ReadCallback), state);

        try
        {
            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    public void ReadCallback(IAsyncResult ar) {

        // Retrieve the state object and the handler socket
        // from the asynchronous state object.
        StateObject state = (StateObject) ar.AsyncState;
        Socket handler = state.workSocket;
        //handler.ReceiveTimeout = 2000;

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

        Send(handler, "paket successfully tranferred");
        state.data = Deserialize(state.rBuffer);

        bool xmlDoc = true;

        try
        {
            XDocument.Parse(state.data.ToString());
        }
        catch
        {
            xmlDoc = false;
        }

        if (xmlDoc)
            XMLHandler.update(state.data.ToString());


    }

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

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

    private 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());
        }
    }

    // Convert a byte array to an Object
    private object Deserialize(byte[] b)
    {
        MemoryStream stream = new MemoryStream(b);
        BinaryFormatter bf = new BinaryFormatter();
        object obj = bf.Deserialize(stream);
        stream.Close();
        return obj;
    }

    // convert object to byte array
    private byte[] Serialize(object obj)
    {
        Stream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(stream, obj);
        byte[] b = null;
        b = new byte[stream.Length];
        stream.Position = 0;
        stream.Read(b, 0, (int)stream.Length);
        stream.Close();
        return b;
    }

}

有人可以帮我解决我的问题吗? 我没有套接字编程经验...

ReadCallback您需要启动另一个BeginReceive ,就像您在AcceptCallback方法中调用BeginAccept的方式一样。

您的代码的一个更严重的问题是您希望每个ReadCallback收到一条完整的消息。 实际上,您可能会收到半个消息,一个字节或三个消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM