Все,Не удается прочитать ответ от сервера Java в IOS клиента с помощью 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. Все, кажется, работает хорошо здесь - следующий клиент 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, который никогда не произойдет.
Мне любопытно, если вы отправляете и получаете строки JSON, почему вы решили написать сервер сокетов для обработки запросов вместо использования HTTP. – davidethell
Попробуйте out_stream.flush() вместо out_stream.close(). socket.close() должен автоматически закрывать как входные, так и выходные потоки. – brettw
@ davidethell Это только часть спецификации - она должна быть настраиваемым сервером, обменивающимся через TCP. – jshort