Can';t使用NSInputStream从iOS客户端中的Java服务器读取响应
全部, 这是我第一次在这里发帖——在过去的几天里,我已经搜索了好几个小时。这不是我制作的第一个客户机/服务器应用程序,我完全不知道出了什么问题 我有一个Java服务器(它能够正确地从我的iOS客户端读取请求——它甚至生成响应并正确地发送,尽管iOS客户端上没有可读取的数据): 所提供的Java函数作为派生它所属类的实例的结果进行调用,并使用ServerSocket的accept()方法的结果进行初始化。这里的一切似乎都很好——下面的Python客户端能够发送请求(甚至读取响应): 在发布iOS客户端之前,我已经使用以下Python服务器对其进行了测试(并且iOS客户端可以按预期进行读/写。这也适用于Python测试客户端): 从Java服务器读取时,iOS客户端永远不会越过以下行: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客
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();
}
}
}