如何在没有服务器的情况下,通过套接字连接两个安卓设备

13

我正试图开发一款安卓应用程序,可以通过点对点连接与其他设备交换数据,而无需使用服务器。请建议我如何实现此功能。提前感谢您。


你可以像处理其他的套接字通信一样处理它。 - HamZa
@HamZa,你能给我一些参考资料吗?因为我对套接字通信还很陌生。 - Faisal Khan
你甚至不想把一个Android设为服务器,而另一个作为客户端。 - MrDumb
这是可能的吗?你有任何参考资料吗? - Faisal Khan
4个回答

8

这是一个使用 Socket 编程而不需要服务器的聊天完整代码。

在我的应用程序中,首先你是客户端并且搜索服务器。当你找不到任何服务器时,你成为服务器并等待客户端连接。

public class MainActivity extends ActionBarActivity {

private Handler handler = new Handler();
private TextView text;
private EditText input;
private Button send;
private Socket socket;
private DataOutputStream outputStream;
private BufferedReader inputStream;
private String DeviceName = "Device";

private boolean searchNetwork() {
    log("Connecting");
    String range = "192.168.56.";
    for (int i = 1; i <= 255; i++) {
        String ip = range + i;
        try {
            socket = new Socket();
            socket.connect(new InetSocketAddress(ip, 9000), 50);
            outputStream = new DataOutputStream(socket.getOutputStream());
            inputStream = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            DeviceName += "1";
            Log.i("Server", DeviceName);
            log("Connected");
            return true;
        } catch (Exception e) {
        }
    }
    return false;

}

private void runNewChatServer() {
    ServerSocket serverSocket;
    try {
        serverSocket = new ServerSocket(9000);
        log("Waiting for client...");
        socket = serverSocket.accept();
        DeviceName += "2";
        log("a new client Connected");
    } catch (IOException e) {
    }

}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    text = (TextView) findViewById(R.id.text);
    input = (EditText) findViewById(R.id.input);
    send = (Button) findViewById(R.id.send);
    Thread thread = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                if (!searchNetwork()) {
                    runNewChatServer();

                }

                outputStream = new DataOutputStream(
                        socket.getOutputStream());
                inputStream = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                while (true) {

                    String Message = inputStream.readLine();
                    if (Message != null) {
                        log(Message);
                    }
                }
            } catch (IOException e) {
                log("Error: IO Exception");
                e.printStackTrace();
            }
        }
    });
    send.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            if (outputStream == null) {
                return;
            }
            try {
                String Message = input.getText().toString() + "\n";
                outputStream.write(Message.getBytes());
                log2(input.getText().toString());
            } catch (IOException e) {
                e.printStackTrace();
            }
            input.setText("");
        }
    });
    thread.start();

}

private void log(final String message) {
    handler.post(new Runnable() {
        String DeviceName2="";
        @Override
        public void run() {
            if (DeviceName.equals("Device1")) {
                DeviceName2 = "Device2";
            }else if(DeviceName.equals("Device2")) {
                DeviceName2 = "Device1";
            }else{
                DeviceName2 = "UnknowDevice";
            }

            text.setText(text.getText() + "\n" + DeviceName2 + " :"
                    + message);

        }
    });
}
private void log2(final String message) {
    handler.post(new Runnable() {

        @Override
        public void run() {


            text.setText(text.getText() + "\n" + "you" + " :"
                    + message);

        }
    });
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.exit(0);
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

}

这里有一个对子网掩码的假设。相反,你可以更好地在网络的广播IP上发送数据报,就像这里详细介绍的那样:http://michieldemey.be/blog/network-discovery-using-udp-broadcast/ - AA_PV

6

你的设计存在一个大问题:

如果没有中央服务器,一些Android设备应该充当客户端,而另一些设备则应充当服务器,但在某些情况下这种方法无法正常工作:

  • 当移动通信提供商分配私有和非公共IP时

  • 当设备连接到Wi-Fi网络,但路由器上未定义NAT规则时。

在这两种情况下,问题是必须充当服务器的设备的监听端口无法访问。


4

Java提供了ServerSocketSocket用于设备之间的通信。您可以将其中一个设备作为服务器,另一个设备作为客户端,在它们之间进行通信,而不需要引入托管在某台机器上的服务器。

另一种更好的选择是使用Wi-Fi对等连接WifiP2pManager可以帮助您实现此目的。这里是一个示例


2
如果您正在寻找本地网络上的P2P,它分为两个部分:
1. 发现对等设备 2. 与对等设备通信
在Android API中,您可以使用 Network Service Discovery APIs Wifi P2P Service Discovery APIs
有一个包装库Salut,它内部使用这些API,并且文档相对较好,也可以使用。
我还创建了P2P库 - Near,直接使用套接字。我在使用Android API时遇到的问题是,发现并不总是发生,底层问题未知。
如果您正在寻找跨互联网的P2P,则{{link4:socket IO}}是一种普遍的解决方案。即使提供IP地址并且它们没有在NAT防火墙后面,Near也应该能够促进传输。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接