[英]Can't read response from Java server in iOS client using NSInputStream
所有,
這是我第一次在這里發帖 - 過去幾天我搜索了幾個小時。 這不是我制作的第一個客戶端/服務器應用程序,而且我完全不知道出了什么問題。
我有一個Java服務器(並且它能夠正確地讀取我的iOS客戶端的請求 - 它甚至可以生成響應並且似乎正確發送它,但是在iOS客戶端上沒有可讀取的數據):
public void run() {
BufferedReader in;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
OutputStream out_stream = this.socket.getOutputStream();
StringBuilder request = new StringBuilder();
String request_buffer;
while ((request_buffer = in.readLine()) != null) {
request.append(request_buffer);
}
out_stream.write(processRequest(request.toString()).getBytes());
out_stream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
提供的Java函數作為生成它所屬的類的實例的結果而被調用,並且它使用ServerSocket的accept()方法的結果進行初始化。 一切似乎在這里工作正常 - 以下Python客戶端能夠發送請求(甚至讀取響應):
DEFAULT_HOST = ''
DEFAULT_PORT = 2012
RECEIVE_BUFFER_SIZE = 4096
if __name__ == "__main__":
import sys, socket
port = DEFAULT_PORT
host = DEFAULT_HOST
if len(sys.argv) > 2:
host = sys.argv[1]
del sys.argv[1]
if len(sys.argv) == 2:
request = sys.argv[1]
print "Requesting: %s" % request
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(request)
s.shutdown(socket.SHUT_WR)
response = ""
message = True
while message:
message = s.recv(RECEIVE_BUFFER_SIZE)
response += message
print "Response: %s" % response
在發布iOS客戶端之前,我已經使用以下Python服務器對其進行了測試(並且iOS客戶端可以按預期讀/寫..這也適用於Python測試客戶端):
import os, sys
DEFAULT_HOST = ''
DEFAULT_PORT = 4150
# Simple test server
DEFAULT_SIZE = 4096
import socket
class Server:
def __init__(self, host, port, root, protocol, debug=True):
self.debug = debug
self.host = host
self.port = port
self.root = root
self.protocol = protocol
def __call__(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((self.host, self.port))
s.listen(5)
while True:
try:
c = s.accept()
print "Connection: %s" % str(c)
request = c[0].recv(DEFAULT_SIZE)
print "Request: %s" % request
try:
response = "test"
if self.debug:
print "Response: %s" % response
except Exception as ex:
print "Error generating response: %s" % ex
if response:
c[0].send(response)
else:
c[0].send("3rr0rZ")
c[0].close()
print
except Exception as ex:
print ex
if __name__ == "__main__":
host = DEFAULT_HOST
port = DEFAULT_PORT
args = sys.argv
# choose a port
if len(args) > 1 and args[1] == "-p":
if len(args) < 3:
raise Exception("Missing Argument for %s" % "-p")
port = int(args[2])
del args[1:3]
else:
port = DEFAULT_PORT
# check if root specified
if len(args) > 1:
root = os.path.realpath(args[1])
del args[1]
else:
root = os.getcwd()
print "Using:"
print "\tHost: %s" % host
print "\tPort: %s" % port
print "\tRoot: %s" % root
print
server = Server(host, port, root)
server()
顯然這是一個簡化的服務器 - 問題不在於如何生成請求。 對於更多背景,請求和響應是JSON字符串,但這並不完全相關。 如前所述,Python客戶端能夠成功地從Java和Python服務器請求和接收響應。 iOS客戶端可以成功地向Python和Java服務器發送請求,但它只能從Python服務器讀取響應。 這是iOS客戶端的相關部分:
- (NSData *)sendMessage:(NSData *)request
{
// Create low-level read/write stream objects
CFReadStreamRef readStream = nil;
CFWriteStreamRef writeStream = nil;
// Create high-level stream objects
NSInputStream *inputStream = nil;
NSOutputStream *outputStream = nil;
// Connect the read/write streams to a socket
CFStreamCreatePairWithSocketToHost(nil, (__bridge CFStringRef) self.address, self.port, &readStream, &writeStream);
// Create input/output streams for the raw read/write streams
if (readStream && writeStream) {
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
inputStream = (__bridge_transfer NSInputStream *)readStream;
[inputStream open];
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[outputStream open];
}
NSLog(@"Sending message to server: %@", request);
[outputStream write:[request bytes] maxLength:[request length]];
[outputStream close];
int size;
int buffer_size = 1024;
uint8_t buffer[buffer_size];
NSMutableData *response = [NSMutableData dataWithLength:0];
while (![inputStream hasBytesAvailable]);
NSLog(@"About to read");
while ([inputStream streamStatus] == NSStreamStatusOpen)
{
if ([inputStream hasBytesAvailable] && (size = [inputStream read:buffer maxLength:buffer_size]) > 0)
{
NSLog(@"Reading response data");
[response appendData:[NSData dataWithBytes:buffer length:size]];
}
}
NSLog(@"\tResponse:%@", response);
return response;
}
從Java服務器讀取時,iOS客戶端永遠不會超過以下行:
while (![inputStream hasBytesAvailable]);
我已經閱讀了我可以找到的各種搜索術語的所有文檔,論壇帖子,問題等,但沒有任何幫助; 我希望這里有人可以解決這個問題! 我已經發布了我正在使用的代碼的略微簡化/扁平版本,但是,再次,這應該足以建立上下文..如果有必要,我會很樂意發布更多代碼,並且我感謝任何幫助或洞察力你可以分享。
我故意不使用NSStreamDelegate,我無法想象這是一個問題。 如果我是,我想象問題只會變成NSStreamEventHasBytesAvailable永遠不會發生。
試試我的代碼,它對我有用。
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();
}
}
}
您的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!
通過始終發送長度后跟數據,您甚至可以發送多條消息,而無需非常輕松地關閉套接字。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.