我了解wifi上的设备之间的直接通信需要通过服务器。如果我有设备A,B,C,且A是组所有者,那么我必须通过以下方式进行通信: 客户端B->服务器A->客户端C, 客户端C->服务器A->客户端B
但是,经过大量研究,我找不到有关如何实现此目标的任何演示。我有用于在1个服务器和1个客户端之间进行通信的工作代码,但我需要能够与通过Wifi P2P连接的多个客户端进行通信。
可在1个服务器和1个客户端之间进行通信的代码:
主要活动:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "nuala";
Button btnOnOff, btnDiscover, btnSend;
ListView listView;
TextView read_msg_box, connectionStatus;
EditText writeMsg;
WifiManager wifiManager;
WifiP2pManager mManager;
WifiP2pManager.Channel mChannel;
BroadcastReceiver mReceiver;
IntentFilter mIntentFilter;
//these 3 are created for getting the information about the devices
List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
String[] deviceNameArray; //used to show the device name in the ListView
WifiP2pDevice[] deviceArray; //used to connect to a device
static final int MESSAGE_READ = 1; //for the handler
ServerClass serverClass;
ClientClass clientClass;
SendReceive sendReceive;
Button myTurnBtn;
// Boolean myTurn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initalWork();
exqListener();
}
//for reading the message sent
//Handler is needed to access variables from other threads
//Handler is the best way to communicate between threads
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch(msg.what){
case MESSAGE_READ:
byte[] readBuff = (byte[]) msg.obj;
String tempMsg = new String(readBuff,0,msg.arg1);
//if tempMsg.equals("go") then show the myTurn button
if (tempMsg.equals("go")) {
myTurnBtn.setVisibility(View.VISIBLE);
Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "not valid", Toast.LENGTH_SHORT).show();
}
// then set MyTurn button visible
//print to screen "success"
//else
//print not valid
read_msg_box.setText(tempMsg);
break;
}
return true;
}
});
private void exqListener() {
btnOnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//turn wifi off if on and on if off
//check status
if (wifiManager.isWifiEnabled()) {
//turn off wifi
wifiManager.setWifiEnabled(false);
btnOnOff.setText("ON");
} else {
//turn on wifi
wifiManager.setWifiEnabled(true);
btnOnOff.setText("OFF");
}
}
});
btnDiscover.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//discovering other devices
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
connectionStatus.setText("Discovery Started");
}
@Override
public void onFailure(int reason) {
connectionStatus.setText("Discovery failed");
}
}); //after discovering devices, need to get the information of the nearby devices (peers)
}
});
//connect to the device that is clicked
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final WifiP2pDevice device = deviceArray[position]; //linking up the position in the ListView with deviceArray position
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
// config.groupOwnerIntent = 15;
config.wps.setup = WpsInfo.PBC;
//connect to the chosen device - only tells of success or failure: need to use ConnectionInfoListener
mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(getApplicationContext(), "Connected to " + device.deviceName, Toast.LENGTH_SHORT).show();
Log.d(TAG, "Connected to: " + device.deviceName);
}
@Override
public void onFailure(int reason) {
Toast.makeText(getApplicationContext(), "Not Connected", Toast.LENGTH_SHORT).show();
}
});
}
});
/* btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String msg = writeMsg.getText().toString();
sendReceive.write(msg.getBytes());
//
}
}); */
myTurnBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//when button is clicked. Send message to receiving device ("go")
String go = "go";
sendReceive.write(go.getBytes()); //pass the go string into the write message
//set button to be invisible
myTurnBtn.setVisibility(View.INVISIBLE);
}
});
}
private void initalWork() {
btnOnOff = findViewById(R.id.onOff);
btnDiscover = findViewById(R.id.discover);
btnSend = findViewById(R.id.sendButton);
listView = findViewById(R.id.peerListView);
read_msg_box = findViewById(R.id.readMsg);
connectionStatus = findViewById(R.id.connectionStatus);
writeMsg = findViewById(R.id.writeMsg);
myTurnBtn = findViewById(R.id.myTurnBtn);
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); //this class provides the API for managing wifi peer to peer connectivity
//anythign regarding the wifi p2p, this manager is used
mChannel = mManager.initialize(this, getMainLooper(), null); //a channel that connects the application to the wifi p2p framework
//most p2p operations require a channel as an argument
mReceiver = new WifiDirectBroadcastReceiver(mManager, mChannel, this);
mIntentFilter = new IntentFilter();
//add all four actions
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
// myTurnBtn =findViewById(R.id.myTurnBtn);
}
//gathering and displaying devices available
WifiP2pManager.PeerListListener peerListListener = new WifiP2pManager.PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peerList) {
if (!peerList.getDeviceList().equals(peers)) { //if the previous list != the current list
peers.clear(); //clear the list
peers.addAll(peerList.getDeviceList()); //add all avaailable peers
//initialise deviceNameArray and deviceArray with a size of as many devices that have been found and stored in peers ArrayList
deviceNameArray = new String[peerList.getDeviceList().size()];
deviceArray = new WifiP2pDevice[peerList.getDeviceList().size()];
int index = 0;
//we have a peerList and two arrays
//using the peerList, we can add all the devices in the two arrays
for (WifiP2pDevice device : peerList.getDeviceList()) { //for each device in the peerList.getDeviceList()
//each iteration, the value of a device is stored in the device variable
deviceNameArray[index] = device.deviceName; //add all devices from deviceNameArray - storing the deviceName
deviceArray[index] = device; //add all devices from deviceArray
index++;
//when loop is finished:
//we have name of all devices in the deviceNameArray
//we have all device objects in the deviceArray
}
//shows the list of devices in the ListView
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1
, deviceNameArray);
listView.setAdapter(adapter);
}
if (peers.size() == 0) {
Toast.makeText(getApplicationContext(), "No devices found", Toast.LENGTH_SHORT).show();
return;
}
}
};
//get information about host and client servers and manage sending and recieving data
WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
final InetAddress groupOwnerAddress = info.groupOwnerAddress; //used for sending and receiving data
//set groupOwn as the Host
if (info.groupFormed && info.isGroupOwner) {
connectionStatus.setText("Host");
myTurnBtn.setVisibility(View.VISIBLE);
serverClass = new ServerClass();
Log.d(TAG, "server thread in groupFromed & groupOwner: " +Thread.currentThread().getId());
serverClass.start();
} else if (info.groupFormed) {
connectionStatus.setText("Client");
clientClass = new ClientClass(groupOwnerAddress);
Log.d(TAG, "a client thread: " +Thread.currentThread().getId());
clientClass.start();
}
}
};
//register the broadcast recevier
@Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
//unregister the broadcast receiver
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
public class ServerClass extends Thread {
Socket socket;
ServerSocket serverSocket;
@Override
public void run() {
try {
serverSocket = new ServerSocket(8888); //port must always be the same - can choose any number
Log.e(TAG, getClass().getSimpleName() + "running on port: " + serverSocket.getLocalPort());
socket = serverSocket.accept(); //socket is ready to accept message
InetAddress add = socket.getInetAddress();
int port = socket.getPort();
Log.e(TAG, "Inet Address : " +add + "port: " +port);
sendReceive = new SendReceive(socket);
sendReceive.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class SendReceive extends Thread {
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
//constructor
public SendReceive(Socket skt) {
socket = skt;
try {
Log.d(TAG, "SendReceive thread: " +Thread.currentThread().getId());
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
//override run method
@Override
public void run() {
byte[] buffer = new byte[1024]; //can choose any value
int bytes;
while (socket != null) { //always read to receive message
try {
bytes = inputStream.read(buffer); //buffer contains the message, bytes contains the number of bytes in the message
// Log.d(TAG, "recieved message: " +buffer);
if (bytes > 0) {
handler.obtainMessage(MESSAGE_READ,bytes,-1,buffer).sendToTarget();
//handler used to deal with threading issues
//obtain message and send the data
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//method to send data
public void write(byte[] bytes) {
try {
outputStream.write(bytes);
Log.d(TAG, "write() Thread: "+Thread.currentThread().getId());
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ClientClass extends Thread {
Socket socket;
String hostAddress;
//hostAddress is provided at runtime when ClientClass is created
public ClientClass(InetAddress hostAddress) {
this.hostAddress = hostAddress.getHostAddress();
socket = new Socket();
}
@Override
public void run() {
try {
socket.connect(new InetSocketAddress(hostAddress, 8888), 500); //same port number as server side
Log.e(TAG, getClass().getSimpleName() + "running on port: " + socket.getLocalPort());
Log.d(TAG, "a client thread: " +Thread.currentThread().getId());
sendReceive = new SendReceive(socket);
sendReceive.start();
Log.d(TAG, "a client thread: " +Thread.currentThread().getId());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Wifi广播接收器
public class WifiDirectBroadcastReceiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private MainActivity mActivity; //think about how this is used and how this can be possible with my app, on the Gameplay activity???
/**
* Constructor with args
* @param manager
* @param channel
* @param activity
*/
public WifiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, MainActivity activity) {
mManager = manager;
mChannel = channel;
mActivity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); //use this to check the current action
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { //indicates whether Wi-Fi p2p is enabled
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); //we will either have the value of the state or the default -1
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { //if wifi is enabled
Toast.makeText(context, "Wifi is ON", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Wifi is OFF", Toast.LENGTH_SHORT).show();
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { //indicates that the available peer list has changed
//do something - get a list of peers by calling WifiP2pManager.requestPeers()
if (mManager!=null) {
mManager.requestPeers(mChannel, mActivity.peerListListener); //pass in peerListListener from mainActivity
}
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { //indicates the state of the wifi p2p connectivity has changed
//do something - respond to a new connection or disconnections
if (mManager == null) {
return;
}
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) { //we are connect with the other device, requestion connection info to find group owner IP
mManager.requestConnectionInfo(mChannel,mActivity.connectionInfoListener);
} else {
mActivity.connectionStatus.setText("Device Disconnected");
}
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { //indicates this device's configuration details have changed
//do something - respond to this device's wifi state changing
}
}
}