Can';t使用NSInputStream从iOS客户端中的Java服务器读取响应

Can';t使用NSInputStream从iOS客户端中的Java服务器读取响应,java,ios,sockets,client-server,java-server,Java,Ios,Sockets,Client Server,Java Server,全部, 这是我第一次在这里发帖——在过去的几天里,我已经搜索了好几个小时。这不是我制作的第一个客户机/服务器应用程序,我完全不知道出了什么问题 我有一个Java服务器(它能够正确地从我的iOS客户端读取请求——它甚至生成响应并正确地发送,尽管iOS客户端上没有可读取的数据): 所提供的Java函数作为派生它所属类的实例的结果进行调用,并使用ServerSocket的accept()方法的结果进行初始化。这里的一切似乎都很好——下面的Python客户端能够发送请求(甚至读取响应): 在发布iOS客

全部,

这是我第一次在这里发帖——在过去的几天里,我已经搜索了好几个小时。这不是我制作的第一个客户机/服务器应用程序,我完全不知道出了什么问题

我有一个Java服务器(它能够正确地从我的iOS客户端读取请求——它甚至生成响应并正确地发送,尽管iOS客户端上没有可读取的数据):

所提供的Java函数作为派生它所属类的实例的结果进行调用,并使用ServerSocket的accept()方法的结果进行初始化。这里的一切似乎都很好——下面的Python客户端能够发送请求(甚至读取响应):

在发布iOS客户端之前,我已经使用以下Python服务器对其进行了测试(并且iOS客户端可以按预期进行读/写。这也适用于Python测试客户端):

从Java服务器读取时,iOS客户端永远不会越过以下行:

while (![inputStream hasBytesAvailable]);
我已经阅读了所有的文档,论坛帖子,问题等,我可以找到各种搜索词,但没有任何帮助;我希望这里有人能解释一下这个问题!我已经发布了我正在使用的代码的一个稍微简化/扁平化的版本,但是,同样,这对于建立上下文来说应该足够了。。如果有必要的话,我会很乐意发布更多的代码,我非常感谢您提供的任何帮助或见解


我故意不使用NSStreamDelegate,我无法想象这会成为一个问题。如果是的话,我会想象这个问题会简单地转化为NSStreamEventHasBytesAvailable,永远不会发生。

您的python服务器和Java服务器是不同的。在python中,您的阅读方式如下:

request = c[0].recv(DEFAULT_SIZE)
它在一个块中最多读取4096字节。而在Java中,您正在使用:

while ((request_buffer = in.readLine()) != null)
in.readLine()将一直阻塞,直到它得到行的结尾,或者直到它得到文件的结尾。在客户端关闭套接字之前,这可能会被卡住。您确定客户端正在正确关闭输出流吗?我不熟悉Objective C,但是关闭输出流可能与关闭套接字的写端不同

如果你负责这条线路的两端,我会让客户端先写一个长度头(两个字节),然后再写那么多数据。然后,服务器可以读取两个字节,计算剩余数据的长度,并精确读取那么多

Length (2-bytes) | Data (length bytes) ---------------------------------------------------------- 0x000C | Hello World! 长度(2字节)|数据(长度字节) ---------------------------------------------------------- 0x000C |世界你好!
通过始终发送长度后跟数据,您甚至可以在不关闭套接字的情况下轻松发送多条消息。

试试我的代码,它适合我

    NSInputStream *inputStream;
    NSOutputStream *outputStream;
    -(void) init{
        NSURL *website = [NSURL URLWithString:@"http://YOUR HOST"];

        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        CFStreamCreatePairWithSocketToHost(NULL,CFBridgingRetain([website host]),9876, &readStream, &writeStream);

        inputStream = (__bridge_transfer NSInputStream *)readStream;
        outputStream = (__bridge_transfer NSOutputStream *)writeStream;
        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream open];
        [inputStream open];

        CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
        CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
    }

- (void) sendMessage {

    // it is important to add "\n" to the end of the line
    NSString *response  = @"Say hello to Ukraine\n";
    NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSUTF8StringEncoding]];
    int sent = [outputStream write:[data bytes] maxLength:[data length]];
    NSLog(@"bytes sent: %d",sent);

    do{
        uint8_t buffer[1024];
        int bytes = [inputStream read:buffer maxLength:sizeof(buffer)];
        NSString *output = [[NSString alloc] initWithBytes:buffer length:bytes encoding:NSUTF8StringEncoding];
        NSLog(@"%@",output);
    } while ([inputStream hasBytesAvailable]);
}

    public class ServerTest {
        public static void main(String[] args) {
            Thread thr = new Thread(new SocketThread());
            thr.start();
        }
    }

    class SocketThread implements Runnable {

        @Override
        public void run() {
            try {
                ServerSocket server = new ServerSocket(9876);
                while (true) {
                    new SocketConnection(server.accept()).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class SocketConnection extends Thread {
        InputStream input;
        PrintWriter output;
        Socket socket;

        public SocketConnection(Socket socket) {
            super("Thread 1");
            this.socket = socket;
            try {
                input = socket.getInputStream();
                output = new PrintWriter(new OutputStreamWriter(
                        socket.getOutputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                byte array[] = new byte[1024];
                while (true) {
                    do {
                        int readed = input.read(array);
                        System.out.println("readed == " + readed + " "
                                + new String(array).trim());
                        String sendString = new String(
                                "Hello Ukraine!".getBytes(),
                                Charset.forName("UTF-8"));
                        output.write(sendString);
                        output.flush();
                    } while (input.available() != 0);
                }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我很好奇,如果您正在发送和接收JSON字符串,为什么您选择编写套接字服务器来处理请求而不是使用HTTP。请尝试out_stream.flush()而不是out_stream.close()。socket.close()应该自动关闭输入流和输出流。@davidethell这只是规范的一部分——它必须是一个通过TCP进行通信的自定义服务器。@brettw使用flush()是我尝试过的许多事情之一,但我在最初的帖子中忘了提到这一点。然而,出现了一个新的症状,情节变得更加复杂。。我从BufferedReader改为直接在套接字的InputStream上调用read。我正在使用while循环,检查计数是否大于0,并调整字节数组的大小以满足完整请求。。事实证明,做这个循环似乎是罪魁祸首。如果我在套接字上执行一次读取(任意大小,比如4096),我就可以读取整个请求并成功地发送一个客户端可以读取的响应。然而,使用循环获取所有数据会导致输出流中断——这不是一个可接受的解决方案,所以我想知道发生了什么?关于不等价性,你是对的。。当然,这是谜题中的另一块。我最感兴趣的是您关于在Objective C中关闭套接字的说明--我对该语言非常陌生,因此我要检查并确保我对该调用的名称不是简单的天真;我在python中遇到过类似的情况,关闭套接字的一端有点不明显。我非常希望不必在请求/响应消息中发送一个大小,尽管我意识到这是一种常见且经认可的方式。我会把调查结果报告回来。。谢谢你的提示!另一个需要添加的东西——在java服务器中,尽管调用可能会被阻塞,但它确实会通过该循环,生成响应,并且似乎会发送响应。在进行了更多的阅读和研究之后,我已经不再深入了。我改变了Python服务器,使其更像Java版本;似乎在iOS客户端中关闭套接字的行为不像“正常”的套接字关闭。。Python服务器的recv()调用应该阻塞,直到接收到数据或发送套接字关闭为止——当iOS客户端关闭套接字时,这种情况永远不会发生!显然,发生了一些奇怪的事情,[outputStream close]没有为服务器(Python或Java)生成套接字关闭事件。我甚至尝试过关闭底层的CFWriteStream。。没什么。我们也尝试过IOS,但在handleStream委托中发现了一种奇怪的行为,因为有时我们能够接收所有响应数据,而大多数时候我们无法接收全部数据。此外,如果有任何同步的手段将出现尝试。任何帮助,真的感谢。
request = c[0].recv(DEFAULT_SIZE)
while ((request_buffer = in.readLine()) != null)
Length (2-bytes) | Data (length bytes) ---------------------------------------------------------- 0x000C | Hello World!
    NSInputStream *inputStream;
    NSOutputStream *outputStream;
    -(void) init{
        NSURL *website = [NSURL URLWithString:@"http://YOUR HOST"];

        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        CFStreamCreatePairWithSocketToHost(NULL,CFBridgingRetain([website host]),9876, &readStream, &writeStream);

        inputStream = (__bridge_transfer NSInputStream *)readStream;
        outputStream = (__bridge_transfer NSOutputStream *)writeStream;
        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream open];
        [inputStream open];

        CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
        CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
    }

- (void) sendMessage {

    // it is important to add "\n" to the end of the line
    NSString *response  = @"Say hello to Ukraine\n";
    NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSUTF8StringEncoding]];
    int sent = [outputStream write:[data bytes] maxLength:[data length]];
    NSLog(@"bytes sent: %d",sent);

    do{
        uint8_t buffer[1024];
        int bytes = [inputStream read:buffer maxLength:sizeof(buffer)];
        NSString *output = [[NSString alloc] initWithBytes:buffer length:bytes encoding:NSUTF8StringEncoding];
        NSLog(@"%@",output);
    } while ([inputStream hasBytesAvailable]);
}

    public class ServerTest {
        public static void main(String[] args) {
            Thread thr = new Thread(new SocketThread());
            thr.start();
        }
    }

    class SocketThread implements Runnable {

        @Override
        public void run() {
            try {
                ServerSocket server = new ServerSocket(9876);
                while (true) {
                    new SocketConnection(server.accept()).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class SocketConnection extends Thread {
        InputStream input;
        PrintWriter output;
        Socket socket;

        public SocketConnection(Socket socket) {
            super("Thread 1");
            this.socket = socket;
            try {
                input = socket.getInputStream();
                output = new PrintWriter(new OutputStreamWriter(
                        socket.getOutputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                byte array[] = new byte[1024];
                while (true) {
                    do {
                        int readed = input.read(array);
                        System.out.println("readed == " + readed + " "
                                + new String(array).trim());
                        String sendString = new String(
                                "Hello Ukraine!".getBytes(),
                                Charset.forName("UTF-8"));
                        output.write(sendString);
                        output.flush();
                    } while (input.available() != 0);
                }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}