Piero
Piero

Reputation: 9273

iPhone Client Talks with Java Server

i'm trying to let an iphone client, talk with a Java Server, this is the Java Server code:

import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class Server {
// a unique ID for each connection
private static int uniqueId;
// an ArrayList to keep the list of the Client
private ArrayList<ClientThread> al;
// if I am in a GUI
private ServerGUI sg;
// to display time
private SimpleDateFormat sdf;
// the port number to listen for connection
private int port;
// the boolean that will be turned of to stop the server
private boolean keepGoing;


/*
 *  server constructor that receive the port to listen to for connection as parameter
 *  in console
 */
public Server(int port) {
    this(port, null);
}

public Server(int port, ServerGUI sg) {
    // GUI or not
    this.sg = sg;
    // the port
    this.port = port;
    // to display hh:mm:ss
    sdf = new SimpleDateFormat("HH:mm:ss");
    // ArrayList for the Client list
    al = new ArrayList<ClientThread>();
}

public void start() {
    keepGoing = true;
    /* create socket server and wait for connection requests */
    try
    {
        // the socket used by the server
        ServerSocket serverSocket = new ServerSocket(port);

        // infinite loop to wait for connections
        while(keepGoing)
        {
            // format message saying we are waiting
            display("Server waiting for Clients on port " + port + ".");

            Socket socket = serverSocket.accept();      // accept connection
            // if I was asked to stop
            if(!keepGoing)
                break;
            ClientThread t = new ClientThread(socket);  // make a thread of it
            al.add(t);                                  // save it in the ArrayList
            t.start();
        }
        // I was asked to stop
        try {
            serverSocket.close();
            for(int i = 0; i < al.size(); ++i) {
                ClientThread tc = al.get(i);
                try {
                    tc.sInput.close();
                    tc.sOutput.close();
                    tc.socket.close();
                }
                catch(IOException ioE) {
                    // not much I can do
                }
            }
        }
        catch(Exception e) {
            display("Exception closing the server and clients: " + e);
        }
    }
    // something went bad
    catch (IOException e) {
        String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
        display(msg);
    }
}
/*
 * For the GUI to stop the server
 */
protected void stop() {
    keepGoing = false;
    // connect to myself as Client to exit statement
    // Socket socket = serverSocket.accept();
    try {
        new Socket("localhost", port);
    }
    catch(Exception e) {
        // nothing I can really do
    }
}
/*
 * Display an event (not a message) to the console or the GUI
 */
private void display(String msg) {
    String time = sdf.format(new Date()) + " " + msg;
    if(sg == null)
        System.out.println(time);
    else
        sg.appendEvent(time + "\n");
}
/*
 *  to broadcast a message to all Clients
 */
private synchronized void broadcast(String message) {
    // add HH:mm:ss and \n to the message
    String time = sdf.format(new Date());
    String messageLf = time + " " + message + "\n";
    // display message on console or GUI
    if(sg == null)
        System.out.print(messageLf);
    else
        sg.appendRoom(messageLf);     // append in the room window

    // we loop in reverse order in case we would have to remove a Client
    // because it has disconnected
    for(int i = al.size(); --i >= 0;) {
        ClientThread ct = al.get(i);
        // try to write to the Client if it fails remove it from the list
        if(!ct.writeMsg(messageLf)) {
            al.remove(i);
            display("Disconnected Client " + ct.username + " removed from list.");
        }
    }
}

// for a client who logoff using the LOGOUT message
synchronized void remove(int id) {
    // scan the array list until we found the Id
    for(int i = 0; i < al.size(); ++i) {
        ClientThread ct = al.get(i);
        // found it
        if(ct.id == id) {
            al.remove(i);
            return;
        }
    }
}

/*
 *  To run as a console application just open a console window and:
 * > java Server
 * > java Server portNumber
 * If the port number is not specified 1500 is used
 */
public static void main(String[] args) {
    // start server on port 1500 unless a PortNumber is specified
    int portNumber = 1500;
    switch(args.length) {
        case 1:
            try {
                portNumber = Integer.parseInt(args[0]);
            }
            catch(Exception e) {
                System.out.println("Invalid port number.");
                System.out.println("Usage is: > java Server [portNumber]");
                return;
            }
        case 0:
            break;
        default:
            System.out.println("Usage is: > java Server [portNumber]");
            return;

    }
    // create a server object and start it
    Server server = new Server(portNumber);
    server.start();
}

/** One instance of this thread will run for each client */
class ClientThread extends Thread {
    // the socket where to listen/talk
    Socket socket;
    ObjectInputStream sInput;
    ObjectOutputStream sOutput;
    // my unique id (easier for deconnection)
    int id;
    // the Username of the Client
    String username;
    // the date I connect
    String date;

    // Constructore
    ClientThread(Socket socket) {
        // a unique id
        id = ++uniqueId;
        this.socket = socket;
        /* Creating both Data Stream */
        System.out.println("Thread trying to create Object Input/Output Streams");
        try
        {
            // create output first
            sOutput = new ObjectOutputStream(socket.getOutputStream());
            sInput  = new ObjectInputStream(socket.getInputStream());
            // read the username
            username = (String) sInput.readObject();
            display(username + " just connected.");
        }
        catch (IOException e) {
            display("Exception creating new Input/output Streams: " + e);
            return;
        }
        // have to catch ClassNotFoundException
        // but I read a String, I am sure it will work
        catch (ClassNotFoundException e) {
        }
        date = new Date().toString() + "\n";
    }

// try to close everything
    private void close() {
        // try to close the connection
        try {
            if(sOutput != null) sOutput.close();
        }
        catch(Exception e) {}
        try {
            if(sInput != null) sInput.close();
        }
        catch(Exception e) {};
        try {
            if(socket != null) socket.close();
        }
        catch (Exception e) {}
    }

    /*
     * Write a String to the Client output stream
     */
    private boolean writeMsg(String msg) {
        // if Client is still connected send the message to it
        if(!socket.isConnected()) {
            close();
            return false;
        }
        // write the message to the stream
        try {
            sOutput.writeObject(msg);
        }
        // if an error occurs, do not abort just inform the user
        catch(IOException e) {
            display("Error sending message to " + username);
            display(e.toString());
        }
        return true;
    }
}
}

for now i'm trying to let login the iphone client, with a simple send of a NSString message, this is what i do in iphone client:

CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"localhost", 1500, &readStream, &writeStream);

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

with only this line of code i can connect to the Java Server and in the server i receive this in the terminal:

Thread trying to create Object Input/Output Streams

so it's connect with the server, then i'm trying to send the username in this way:

NSString *username  = @"user";
NSData *data = [[NSData alloc] initWithData:[username dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];

but in the server terminal i receive this:

Exception creating new Input/output Streams: java.io.StreamCorruptedException: invalid stream header: 69616D3A

i have also tried to send the message in this way:

NSData *_data=[username dataUsingEncoding:NSUTF8StringEncoding]; 
int data_len = [_data length];
uint8_t *readBytes = (uint8_t *)[_data bytes];
int byteIndex=0;
unsigned int len=0;
while (TRUE) {
len = ((data_len - byteIndex >= 40960) ? 40960 : (data_len-byteIndex));
if(len==0)
break;
uint8_t buf[len]; 
(void)memcpy(buf, readBytes, len);
len = [outputStream write:(const uint8_t *)buf maxLength:len]; byteIndex += len;
readBytes += len; 
}

but also in this way i receive the same exception, how i can send a messagge to a java server?

Upvotes: 1

Views: 876

Answers (1)

Daij-Djan
Daij-Djan

Reputation: 50089

No concrete help as to your code BUT consider using AFNetwork. (on github) networking is always hard and that framework is just awesome.

AH ..your trying to write to object streams on the java side.. those use a proprietary byte format. you dont send the data in the expected way (the wrong bytes => no java objects)

I would really go with JSON,xml or a simpler version of a 'protocol'

Upvotes: 1

Related Questions