java - iPhone 客户端与 Java 服务器对话

标签 java iphone objective-c client-server

我正在尝试让 iPhone 客户端与 Java 服务器对话,这是 Java 服务器代码:

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;
    }
}
}

现在我正在尝试通过简单地发送一条 NSString 消息来登录 iphone 客户端,这就是我在 iphone 客户端中所做的:

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];

仅使用这行代码,我就可以连接到 Java 服务器,并且在服务器中我在终端中收到此代码:

Thread trying to create Object Input/Output Streams

所以它与服务器连接,然后我尝试以这种方式发送用户名:

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

但在服务器终端中我收到此消息:

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

我也尝试过以这种方式发送消息:

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; 
}

但同样以这种方式我收到相同的异常,我如何向java服务器发送消息?

最佳答案

对您的代码没有具体帮助,但请考虑使用 AFNetwork。 (在github上) 网络总是很困难,而这个框架非常棒。

啊..您试图在java端写入对象流..它们使用专有的字节格式。您没有以预期的方式发送数据(错误的字节=>没有java对象)

我真的会选择 JSON、xml 或更简单版本的“协议(protocol)”

关于java - iPhone 客户端与 Java 服务器对话,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13273320/

相关文章:

java - Jest 客户端/ElasticSearch 集群信息

ios - 如何从相机胶卷和照片库中选择多个视频?

javascript - 如何使用 JavaScript 判断应用程序是否安装在 ios 设备上?

objective-c - 测试 NSImage/CGImageRef 是否完全透明的最佳方法

iphone - 发送到实例的无法识别的选择器

ios - 以编程方式更改UIImage的位置

java - Android 蓝牙 LE 屏蔽 UUID 过滤器

java - CriteriaBuilder 查询在两列之间使用 Like

Java 获取输出 CallableStatement JDBC

ios - 通过 AVPlayer 播放实时 URL 流