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

时间:2014-03-20 14:39:18

标签: c# sockets object networking

我在客户端套接字(同步)/服务器套接字(异步)环境中遇到以下问题。 如果我从客户端向服务器发送多条消息,第一条消息完成没有任何问题,客户端将毫无问题地收到。当我发送第二条消息时,只需要几个字节。它似乎不是一个客户端问题,因为它看起来客户端始终发送整个消息。疯狂的是,如果我完全停止客户端上的项目并再次启动第一条消息再次完成,那么服务器组件也会一直运行。

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

// CLIENT:

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

    }
}

// SERVER:

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

}

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

1 个答案:

答案 0 :(得分:2)

ReadCallback中,您需要开始另一个BeginReceive,就像您在BeginAccept方法中致电AcceptCallback一样。

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