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

标签 c# sockets object networking

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

我想做的事...
基本上,我想传输不同的对象(大多数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;
    }

}

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

最佳答案

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

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

关于c# - 网络套接字-仅第一条消息总是会完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22536304/

相关文章:

c# - 在本地运行的 Azure 保管库

c# 加载大量图像时出现内存不足异常

c# - Ajax AutoCompleteExtender - 为什么此代码不起作用?

java - 使用服务器套接字后如何关闭端口

javascript - 从数组中删除不会更新变量内的引用?

c# - 一个字符的不同 ASCII 值

java - 有什么办法可以让UDP丢包更低一些吗?

C - 同时接收和处理来自 unix 套接字的数据

javascript - 在对象的对象数组中查找属性的最大值

java - 可靠地将任何对象转换为字符串,然后再返回