我有一个Android应用程序需要让多个设备连接。 一台设备应作为群主,并发出指令到所有客户端做具体的事情。 我想这是相当于一个无线手持游戏,一个玩家的主机。
我有几个问题,所以我会尽量让他们简洁。 即使一个答案,只是第一个将帮助。
首先,我已经成功地配对一台服务器和一个客户端的手机使用套接字。 我这样做是使用Android的Wi-Fi Direct技术( 这里描述 )。 本教程是有用的,但可惜不是很透彻,尤其是在描述一个一对多的连接。 一旦对等列表中发现,套接字连接可以打开。 我能够使用一个线程连接两个设备服务器( 使用这个例子 ),如下所示:
public class ServerThread implements Runnable {
public void run() {
(Code...)
client = serverSocket.accept();
(...other code here.)
}
}
客户端将创建下列按下一个按钮(我认为,仍然试图让我的头在我修改后的代码):
public class MusicClientThread implements Runnable {
Socket socket = new Socket(serverAddr, port);
while (connected) {
//(Other code here.)
while ((line = in.readLine()) != null) {
//While there are still messages coming
}
}
socket.close();
//(Other code here too.)
}
所以,我想我的第一个问题是:如何将允许连接更多的客户? 我ServerThread是指一个客户端变量上,所以我不看我怎么会允许不同数量的(我的应用程序是从2到10个用户瞄准任何东西)我也不知道我的所有不同的客户进行区分的正确方法。 我唯一的猜测是,我会用每部手机的唯一的IP地址。
我的第二个问题是,一旦我建立了多个客户端/对等连接,我怎么会那么发送和接收指令,以他们是否正确? 目前,我的单台服务器等待指令,并在接收它,发出响应指令。 我需要它,使服务器能够从一开始就发送指令,通过按键操作,这些结果是在客户端设备可见。
我希望我已经都清楚了!
你必须开始一个新的线程为每个客户端,插座需要为自己运行的线程(因为它等待输入的大部分时间)。 例如,这可以进行(在该简化的方式):
public class ThreadHandler extends Thread {
private ArrayList<ServerThread> serverThreads = new ArrayList<ServerThread>();
public void run() {
while (!isInterrupted()) { //You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
(Code...)
ServerThread thread = new ServerThread(serverSocket.accept());
serverThreads.add(thread);
thread.start();
}
}
public void doSomethingOnAllThreads() {
for (ServerThread serverThread : serverThreads) {
serverThread.otherMethod();
}
}
}
凡ServerThread看起来是这样的:
public class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
(...other code here.)
}
public void otherMethod() {
//Signal to the thread that it needs to do something (which should then be handled in the run method)
}
}
我有一个谷歌电视盒。 我有两部手机。
在GoogleTV的盒子我运行一个服务器。 服务器在端口6001一个ServerSocket的同样的服务器有两个插座,用于两个客户端
所述第一设备连接到服务器并使用套接字号一个第二其他....
我可以从2个设备连接到谷歌电视盒插槽点大后指出错误信息,并显示他们在电视上。
我用以下解决方案:
所述移动客户端(2个装置)
创建一个空白的活动一个新的Android项目,该代码复制到。 创建用于包含的EditText和一个按钮客户端的布局。 请务必将Internet和访问网络权限在AndroidManifest.xml! 和编辑serverIpAddress在这个文件到你的服务器访问的IP。
package de.android.googletv.gameclient;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Random;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/**
*
*
*
*/
public class FullscreenActivity extends Activity {
private Socket socket;
private String serverIpAddress = "192.168.22.253"; // GOOGLE TV IP
private static final int PLAYER_1_SERVERPORT = 6001;
private Button bt;
private TextView tv;
String DEVICE_NAME;
private class ConnectToServer extends AsyncTask {
@Override
protected Object doInBackground(Object... params) {
System.out.println("connecting to server...");
try {
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
socket = new Socket(serverAddr, PLAYER_1_SERVERPORT);
} catch (UnknownHostException e1) {
System.out.println("ERROR REACHING SERVER! 1");
e1.printStackTrace();
} catch (IOException e1) {
System.out.println("ERROR REACHING SERVER! 2");
e1.printStackTrace();
}
System.out.println("Done!");
return params;
}
protected void onPostExecute() {
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
DEVICE_NAME = android.os.Build.MODEL;
Button exit = (Button) findViewById(R.id.dummy_button);
exit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.exit(1);
}
});
new ConnectToServer().execute("");
tv = (TextView) findViewById(R.id.editText1);
bt = (Button) findViewById(R.id.button1);
bt.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
Random rnd = new Random();
EditText et = (EditText) findViewById(R.id.editText1);
String str = DEVICE_NAME + " ID" + rnd.nextInt() + " says: " + et.getText().toString();
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())),true
);
out.println(str);
Log.d("Client", "Client sent message");
}
catch (UnknownHostException e) {
tv.setText("UnknownHostException");
e.printStackTrace();
}
catch (IOException e) {
tv.setText("IOException");
e.printStackTrace();
}
catch (Exception e) {
tv.setText("Exception");
e.printStackTrace();
}
}
});
}
}
对于服务器(谷歌电视盒)
创建空白的活动一个新的Android项目,该代码复制到。 创建布局,只有一个文本框,请务必将Internet和访问网络权限在AndroidManifest.xml!
package de.android.googletv.gameserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
*
*
*
*/
public class FullscreenActivity extends Activity {
// server socket
ServerSocket ss_plr1 = null;
public static final int SERVERPORT_1 = 6001;
int nr_connections = 0;
// socket for player1
Socket s1;
// socket for player2
Socket s2;
Thread myCommsThread = null;
protected static final int MSG_ID = 0x1337;
String mClientMsg = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
Button exit = (Button) findViewById(R.id.dummy_button);
exit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.exit(1);
}
});
TextView tv = (TextView) findViewById(R.id.fullscreen_content);
tv.setText("Nothing from client yet");
myCommsThread = new Thread(new CommsThread());
myCommsThread.start();
}
@Override
protected void onStop() {
super.onStop();
try {
// make sure you close the socket upon exiting
ss_plr1.close();
}
catch (IOException e) {e.printStackTrace(); }
}
Handler myUpdateHandler = new Handler() {
public void handleMessage(Message msg) {
System.out.println("handleMessage("+msg+")");
switch (msg.what) {
case MSG_ID:
TextView tv = (TextView) findViewById(R.id.fullscreen_content);
tv.setText((String)msg.obj);
break;
default:
break;
}
super.handleMessage(msg);
}
};
class CommsThread implements Runnable {
public void run() {
System.out.println("creating new sockets...");
try {
ss_plr1 = new ServerSocket(SERVERPORT_1 );
if (s1 == null)
s1 = ss_plr1.accept();
if (s2 == null)
s2 = ss_plr1.accept();
}
catch (IOException e) {e.printStackTrace();}
new Thread(new ConnectionHandler(s1, myUpdateHandler)).start();
new Thread(new ConnectionHandler(s2, myUpdateHandler)).start();
}
}
}
...以及服务器需要的是螺纹消息,连接处理器...
创建服务器项目中的其他类叫做:“ConnectionHandler.java”这个代码复制到。 它处理异步连接。
package de.android.googletv.gameserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import android.os.Handler;
import android.os.Message;
public class ConnectionHandler implements Runnable {
Socket m_socket;
Handler m_updateHandler;
public ConnectionHandler(Socket socket, Handler updateHandler) {
m_socket = socket;
m_updateHandler = updateHandler;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
BufferedReader input = new BufferedReader(new InputStreamReader(m_socket.getInputStream()));
String st = null;
st = input.readLine();
Message m = new Message();
m.what = 0x1337;
m.obj = st;
m_updateHandler.sendMessage(m);
}
catch (IOException e) { e.printStackTrace();}
}
}
}
这是不是最好的解决方案。 多个“不好听”的代号。 System.exit(1)例如。 而且它只有两个设备的支持。 但是,它适用于多台设备,和IM相当确信你将修改它为你的目的。 它基于三个网络资源和额外attemps从我自己,使其工作。 它只是我的原型....
我不能链接到他们:( ...较少的声誉。
如果你建立并运行寄托都应该是这样的:
https://plus.google.com/u/0/109268217221135029753/posts/3iz6SF1hiJa