在套接字中找不到数据,但肯定收到了回复

时间:2016-02-09 22:25:49

标签: java c# sockets tcp

我目前正在编写一个程序,通过TCP数据包与托管在单独设备上的服务器进行通信。写入服务器工作正常,但我似乎永远无法读取响应。我很肯定有一个回应,因为在嗅探网络数据包时,我看到来自设备的传入数据包,尽管程序从未检测到它。

public class SocketTest
{
    private Socket socket;
    private int currentSequence = 0;


    public static void main(String[] args)
    {
        new SocketTest();
    }


    public SocketTest()
    {
        try
        {
            System.out.println("Connecting");
            socket = new Socket("192.168.1.8", 8000);
            System.out.println("Connected!");

            System.out.println("Pinging...");
            sendPacket(0, 3, null, 0);
            System.out.println("Pinged!");

            System.out.println("Reading..");
            while (socket.isConnected())
            {
                byte[] res = new byte[84];
                socket.getInputStream().read(res);
                System.out.println("Read!");
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    public void sendPacket(int type, int command, int[] args, int length)
    {
        int t = 0;
        currentSequence += 1000;
        byte[] resultBuffer = new byte[84];

        byte[] payload1 = getBytes(0x12345678);
        System.arraycopy(payload1, 0, resultBuffer, t, payload1.length);
        t += 4;

        byte[] payload2 = getBytes(currentSequence);
        System.arraycopy(payload2, 0, resultBuffer, t, payload2.length);
        t += 4;

        byte[] payload3 = getBytes(type);
        System.arraycopy(payload3, 0, resultBuffer, t, payload3.length);
        t += 4;

        byte[] payload4 = getBytes(command);
        System.arraycopy(payload4, 0, resultBuffer, t, payload4.length);
        for (int i = 0; i < 16; i++)
        {
            t += 4;
            int arg = 0;
            if (args != null)
            {
                arg = args[i];
            }
            byte[] payloadArg = getBytes(arg);
            System.arraycopy(payloadArg, 0, resultBuffer, t, payloadArg.length);
        }
        t += 4;

        byte[] payload5 = getBytes(length);
        System.arraycopy(payload5, 0, resultBuffer, t, payload5.length);

        write(resultBuffer, 0, resultBuffer.length);
    }


    private void write(byte[] buffer, int startOffset, int length)
    {
        DataOutputStream out;
        try
        {
            out = new DataOutputStream(socket.getOutputStream());
            out.write(buffer, startOffset, length);
            out.flush();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    private byte[] getBytes(int value)
    {
        ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder());
        buffer.putInt(value);
        return buffer.array();
    }

}

我尝试了一堆不同的阅读方法..多线程,心跳等。但每次我使用InputStream的read()方法时,它都会阻塞,因为没有数据要读取,而套接字肯定是打开的因为结果不是-1。

这是我在我的程序中使用的实际读取方法(上面的代码是缩短的xample)

private int read(byte[] buffer, int offset, int length)
{
    int res = 0;

    DataInputStream bis;
    try
    {
        bis = new DataInputStream(socket.getInputStream());

        if (bis.available() > 0)
        {
            System.out.println("Waiting bytes: " + bis.available());
            System.out.println("buffer = [" + Arrays.toString(buffer) + "], offset = [" + offset + "], length = [" + length + "]");
            res = bis.read(buffer, offset, length);
        }
        else
        {
            NTR.getLogger().debug("Available: " + bis.available());
        }
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

    return res;
}

有趣的是,C#版本的代码运行得很好。

namespace ntrclient
{
    public class NtrClient
    {
        public delegate void LogHandler(string msg);

        private readonly object _syncLock = new object();

        private uint _currentSeq;
        private int _heartbeatSendable;
        public string Host;
        private string _lastReadMemFileName;
        private uint _lastReadMemSeq;
        public NetworkStream NetStream;
        public Thread PacketRecvThread;
        public int Port;
        public volatile int progress = -1;
        public TcpClient Tcp;
        public event LogHandler OnLogArrival;

        private int ReadNetworkStream(Stream stream, byte [] buf, int length)
        {
            var index = 0;
            var useProgress = length > 100000;
            do
            {
                if (useProgress)
                {
                    progress = (int) ((double) index / length * 100);
                }
                var len = stream.Read(buf, index, length - index);
                if (len == 0)
                {
                    Console.WriteLine("No data to be read");
                    return 0;
                }
                Console.WriteLine("Read " + len + " datas");
                index += len;
            } while (index < length);
            progress = -1;
            Console.WriteLine("Length: " + length + ", Buffer: " + buf);
            return length;
        }

        private void PacketRecvThreadStart()
        {
            var buf = new byte [84];
            var args = new uint [16];
            var stream = NetStream;

            while (true)
            {
                try
                {
                    var ret = ReadNetworkStream(stream, buf, buf.Length);
                    if (ret == 0)
                    {
                        break;
                    }
                    var t = 0;
                    var magic = BitConverter.ToUInt32(buf, t);
                    t += 4;
                    var seq = BitConverter.ToUInt32(buf, t);
                    t += 4;
                    var type = BitConverter.ToUInt32(buf, t);
                    t += 4;
                    var cmd = BitConverter.ToUInt32(buf, t);
                    for (var i = 0; i < args.Length; i++)
                    {
                        t += 4;
                        args [i] = BitConverter.ToUInt32(buf, t);
                    }
                    t += 4;
                    var dataLen = BitConverter.ToUInt32(buf, t);
                    if (cmd != 0)
                    {
                        Log($"packet: cmd = {cmd}, dataLen = {dataLen}");
                    }

                    if (magic != 0x12345678)
                    {
                        Log($"broken protocol: magic = {magic}, seq = {seq}");
                        break;
                    }

                    if (cmd == 0)
                    {
                        if (dataLen != 0)
                        {
                            var dataBuf = new byte [dataLen];
                            ReadNetworkStream(stream, dataBuf, dataBuf.Length);
                            var logMsg = Encoding.UTF8.GetString(dataBuf);
                            Log(logMsg);
                        }
                        lock (_syncLock)
                        {
                            _heartbeatSendable = 1;
                        }
                        continue;
                    }
                    if (dataLen != 0)
                    {
                        var dataBuf = new byte [dataLen];
                        ReadNetworkStream(stream, dataBuf, dataBuf.Length);
                        HandlePacket(cmd, seq, dataBuf);
                    }
                }
                catch (Exception e)
                {
                    Log(e.Message);
                    break;
                }
            }

            Log("Server disconnected.");
            Disconnect(false);
        }

        public void ConnectToServer()
        {
            if (Tcp != null)
            {
                Disconnect();
                Log("Disconnected from previous server, connecting to new one");
            }

            new Thread(() =>
            {
                //Thread.CurrentThread.IsBackground = true;
                Tcp = new TcpClient { NoDelay = true };
                Tcp.Connect(Host, Port);
                _currentSeq = 0;
                NetStream = Tcp.GetStream();
                _heartbeatSendable = 1;
                PacketRecvThread = new Thread(PacketRecvThreadStart);
                PacketRecvThread.Start();
                Program.getMain().Connected = true;
                Log("Server connected.");
            }).Start();
        }

        public void Disconnect(bool waitPacketThread = true)
        {
            try
            {
                Tcp?.Close();
                if (waitPacketThread)
                {
                    PacketRecvThread?.Join();
                }

                // Not connected anymore
                Program.getMain().Connected = false;
                Log("Server disconnected.");
            }
            catch (Exception ex)
            {
                Log(ex.Message);
            }
            Tcp = null;
        }

        public void SendPacket(uint type, uint cmd, uint [] args, uint dataLen)
        {
            var t = 0;
            _currentSeq += 1000;
            var buf = new byte [84];
            BitConverter.GetBytes(0x12345678).CopyTo(buf, t);
            t += 4;
            BitConverter.GetBytes(_currentSeq).CopyTo(buf, t);
            t += 4;
            BitConverter.GetBytes(type).CopyTo(buf, t);
            t += 4;
            BitConverter.GetBytes(cmd).CopyTo(buf, t);
            for (var i = 0; i < 16; i++)
            {
                t += 4;
                uint arg = 0;
                if (args != null)
                {
                    arg = args [i];
                }
                BitConverter.GetBytes(arg).CopyTo(buf, t);
            }
            t += 4;
            BitConverter.GetBytes(dataLen).CopyTo(buf, t);
            NetStream.Write(buf, 0, buf.Length);
        }

        public void SendHeartbeatPacket()
        {
            if (Tcp == null)
                return;

            lock (_syncLock)
            {
                if (_heartbeatSendable != 1)
                    return;

                _heartbeatSendable = 0;
                SendPacket(0, 0, null, 0);
            }
        }

    }
}

老实说,我很难过。我注意到C#的NetworkStream读写方法与java不同,但我不确切地知道它们有多么不同,或者它是否有所不同。

提前致谢!

0 个答案:

没有答案