Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TCP communication between Swift iOS and Java Sockets

I'm trying to establish a communication between my Java application and the relative (work in progress) iOS application. After sockets are opened, the iOS application (client) write an "handshake" string into stream and then it wait on read stream (I think). Contemporary the Java application (server, started before the iOS application) open with success the socket and wait on BufferedReader for read the "handshake" and at this point both applications are blocked. I don't understand how it is possible?

Follow the part of iOS code:

public class Client: NSObject, NSStreamDelegate  {

var serverAddress: CFString
let serverPort: UInt32 = 50000

private var inputStream: NSInputStream!
private var outputStream: NSOutputStream!
private var connecting:Bool

init(ip:String) {
    serverAddress = ip
    connecting = false

    super.init()

    connect()
}

func connect() {
    connecting = true

    while connecting {
        print("connecting...")

        var readStream:  Unmanaged<CFReadStream>?
        var writeStream: Unmanaged<CFWriteStream>?

        CFStreamCreatePairWithSocketToHost(nil, self.serverAddress, self.serverPort, &readStream, &writeStream)

        // Documentation suggests readStream and writeStream can be assumed to
        // be non-nil. If you believe otherwise, you can test if either is nil
        // and implement whatever error-handling you wish.

        self.inputStream = readStream!.takeRetainedValue()
        self.outputStream = writeStream!.takeRetainedValue()

        self.inputStream.delegate = self
        self.outputStream.delegate = self

        self.inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
        self.outputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

        self.inputStream.open()
        self.outputStream.open()

        // send handshake

        let handshake: NSData = "handshake".dataUsingEncoding(NSUTF8StringEncoding)!
        let returnVal = self.outputStream.write(UnsafePointer<UInt8>(handshake.bytes), maxLength: handshake.length)
        print("written: \(returnVal)")


        // wait to receive handshake

        let bufferSize = 1024
        var buffer = Array<UInt8>(count: bufferSize, repeatedValue: 0)

        print("waintig for handshake...")

        let bytesRead = inputStream.read(&buffer, maxLength: bufferSize)
        if bytesRead >= 0 {
            var output = NSString(bytes: &buffer, length: bytesRead, encoding: NSUTF8StringEncoding)
            print("received from host \(serverAddress): \(output)")
        } else {
            // Handle error
        }

        connecting = false

        self.inputStream.close()
        self.outputStream.close()
    }


}

public func stream(stream: NSStream, handleEvent eventCode: NSStreamEvent) {
    print("stream event")

    if stream === inputStream {
        switch eventCode {
        case NSStreamEvent.ErrorOccurred:
            print("input: ErrorOccurred: \(stream.streamError?.description)")
        case NSStreamEvent.OpenCompleted:
            print("input: OpenCompleted")
        case NSStreamEvent.HasBytesAvailable:
            print("input: HasBytesAvailable")

            // Here you can `read()` from `inputStream`

        default:
            break
        }
    }
    else if stream === outputStream {
        switch eventCode {
        case NSStreamEvent.ErrorOccurred:
            print("output: ErrorOccurred: \(stream.streamError?.description)")
        case NSStreamEvent.OpenCompleted:
            print("output: OpenCompleted")
        case NSStreamEvent.HasSpaceAvailable:
            print("output: HasSpaceAvailable")

            // Here you can write() to `outputStream`
            break

        default:
            break
        }
    }

}

}

Follow the part of Java code (it work perfectly between other computers using the same Java application):

public void run()
{
    System.out.println("Server.java: waiting for connection");

    //accept
    try
    {
        serverSocket = new ServerSocket(portNumber);
        clientSocket = serverSocket.accept();
        reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

        System.out.println("Server.java: connected to " + clientSocket.getInetAddress());

        // check for input request type
        String line = reader.readLine();    // <----BLOCKED HERE!

        if(line.equals("handshake"))
        {
            connected = true;

            // send acceptation
            System.out.println("Server.java: Sending handshake, waiting response");
            writer.write("handshake");
            writer.newLine();
            writer.flush();

            // .... and the rest of code...

When I close the iOS application the Java application unlock from the read, print correctly the received handshake and then continue his job. Someone can help me please?

like image 303
sgiraz Avatar asked Jul 22 '16 19:07

sgiraz


People also ask

Do java sockets use TCP?

Yes, Socket and ServerSocket use TCP/IP. The package overview for the java.net package is explicit about this, but it's easy to overlook.

How do I connect sockets in Swift?

First, we need to create a Socket class: Create a class (I called it SocketServer), this class is going to connect to the desired socket using host & port . Later on, we're going to declare a protocol ( SocketDelegate ) that this class calls its methods when InputStream has available response.

What are TCP IP sockets in java?

TCP/IP sockets are used to implement reliable two-way, persistent, point-to-point streaming connections between hosts on the Internet. The Java I/O system can use sockets to connect to other programs on the local system or on other systems on the Internet.


1 Answers

I think your problem is that you never end the line in Swift program.

What readLine does according to BufferReader's documentation:

"Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed."

This means that it expects either a newline character, or the end of the communication. Since your Swift application doesn't send any newline char and doesn't close the stream, the client just waits.

Try to put a line feed ('\n') or a carriage return ('\r') and see how it goes.

like image 59
Vlad Bogdan Avatar answered Sep 18 '22 19:09

Vlad Bogdan