Sample-多部手机同局域网通信

本文介绍了一种基于Android平台的局域网内多手机互相通信的实现方案。客户端通过Socket连接服务器,并发送消息;服务器端接收消息并显示。涉及的技术包括Socket编程、线程处理及UI更新。

一: 主要功能
实现多手机在同一局域网互相通信

二:客户端主要代码

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;

import android.app.Activity;
import android.app.Instrumentation;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;


public class MinaClientActivity extends Activity implements View.OnClickListener {

    private Socket mClientSocket;
    private String mSendContent;
    private TextView mTvConnectServer;
    private Button mBtnSend;
    private EditText mEtSendContent;
    private EditText mEtInputIp;
    private ConnectServerThread mConnectServerThread;
    private SendMsgServerThread mSendMsgServerThread;
    private PrintWriter mPrintWriterOut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mina_server);
        mTvConnectServer = (TextView) findViewById(R.id.tv_connect_server);
        mBtnSend = (Button) findViewById(R.id.bt_send);
        mEtSendContent = (EditText) findViewById(R.id.et_send_message);
        mEtInputIp = (EditText) findViewById(R.id.et_input_ip);
        mBtnSend.setOnClickListener(this);
        mTvConnectServer.setOnClickListener(this);
        mConnectServerThread = new ConnectServerThread();
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            //发送消息
            case R.id.bt_send:
                Toast.makeText(this,"send click",Toast.LENGTH_SHORT).show();
                mSendMsgServerThread = new SendMsgServerThread();
                Thread sendThread = new Thread(mSendMsgServerThread);
                sendThread.start();
//                sendKeyEvent(KeyEvent.KEYCODE_BACK);
                break;
            //连接server
            case R.id.tv_connect_server:
                Toast.makeText(this,"connect click",Toast.LENGTH_SHORT).show();
                Thread connectThread = new Thread(mConnectServerThread);
                connectThread.start();
                break;
        }
    }

    private class ConnectServerThread implements Runnable {

        @Override
        public void run() {
            try {
                String ip = mEtInputIp.getText().toString().replaceAll(" ","");
                mClientSocket = new Socket();
                mClientSocket.connect(new InetSocketAddress(ip, 30000), 1000);
            } catch (SocketTimeoutException e) {
                MyLog.logD("ConnectServerThread SocketTimeoutException");
            } catch (IOException e) {
                MyLog.logD("ConnectServerThread IOException" + e.toString());
            }
            MyLog.logD("ConnectServerThread mClientSocket.isConnected() " + mClientSocket.isConnected());
        }
    }

    private class SendMsgServerThread implements Runnable{

        @Override
        public void run() {
            try {
                //输出
                mPrintWriterOut = new PrintWriter ( mClientSocket.getOutputStream());
                String sendMsg = mEtSendContent.getText().toString().replaceAll(" ","");
                mPrintWriterOut.write(sendMsg);
                mPrintWriterOut.flush();
            } catch (SocketTimeoutException e) {
                MyLog.logD("sendMessageToServer SocketTimeoutException");
            } catch (IOException e) {
                MyLog.logD("sendMessageToServer IOException");
            }
        }
    }
}

对应的xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="输入IP"
        android:padding="10dp"
        android:ems="10"
        android:layout_margin="10dp"
        android:background="#fa870a"
        android:id="@+id/et_input_ip" />

    <TextView
        android:id="@+id/tv_connect_server"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="#ffffff"
        android:background="#fa870a"
        android:layout_margin="10dp"
        android:text="连接server"
        android:padding="10dp"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:hint="发送的内容"
        android:padding="10dp"
        android:layout_margin="10dp"
        android:background="#fa870a"
        android:ems="10"
        android:id="@+id/et_send_message" />

    <Button
        android:id="@+id/bt_send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="10dp"
        android:textColor="#ffffff"
        android:background="#fa870a"
        android:layout_margin="10dp"
        android:text="发送"/>

</LinearLayout>

三: Server端主要代码


import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

import android.app.Instrumentation;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.Context;
import android.view.KeyEvent;
import android.widget.TextView;


public class AsLearningMainActivity extends Activity {

    public static TextView mTvReceiveMsg;

    public static TextView mTvIp;
    private InterActionClientThread mInterActionClientThread;
    private InputStream mClientSocketIn;
    private String mReceiveMsg = "";
    private int mUpdateReceiveMsgWhat = 0x11;
    private HashMap<String,String> mKeyMap = new HashMap<String,String>();

    public Handler mHandler = new Handler() {
        @Override
        public void handleMessage(android.os.Message msg) {
            if(msg.what == mUpdateReceiveMsgWhat){
                String receiveMsg = msg.obj.toString();
                mTvReceiveMsg.setText(receiveMsg);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_as_learning_main);
        mTvReceiveMsg = (TextView) findViewById(R.id.tv_receive_msg);
        mTvIp = (TextView) findViewById(R.id.tv_ip);
        String ip = getlocalip();
        mTvIp.setText("IP addresss:" + ip);
        mInterActionClientThread = new InterActionClientThread();
        Thread sendThread = new Thread(mInterActionClientThread);
        sendThread.start();
    }

    /**
     * 或取本机的ip地址
     */
    private String getlocalip() {
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        int ipAddress = wifiInfo.getIpAddress();
        if (ipAddress == 0) return null;
        return ((ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "."
                + (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff));
    }

    private class InterActionClientThread implements Runnable{

        @Override
        public void run() {
            try {
                ServerSocket mServerSocket = new ServerSocket(30000);
                while (true)
                {
                //accept是阻塞的 因此该方法只有当有连接的时候才继续执行
                    Socket socket = mServerSocket.accept();
                    mClientSocketIn = socket.getInputStream();
                    MyLog.logD("InterActionClientThread socket.isConnected() " + socket.isConnected() + " " + socket.getInetAddress().toString());
                    byte[] bt = new byte[10];
                    mClientSocketIn.read(bt);
                    mReceiveMsg = new String(bt,"UTF-8");
                    MyLog.logD("InterActionClientThread mReceiveMsg " + mReceiveMsg);
                    if (mReceiveMsg != null && mReceiveMsg != "exit")
                    {
                        Message msg = new Message();
                        msg.what = mUpdateReceiveMsgWhat;
                        msg.obj = mReceiveMsg + socket.getInetAddress().toString();
                        mHandler.sendMessage(msg);
                        sendKeyEvent(KeyEvent.KEYCODE_BACK);
                    }else if (mReceiveMsg == null || mReceiveMsg == "exit"){
                        break;
                    }
                }
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                MyLog.logD("InterActionClientThread IOException");
            }
        }
    }


    public void sendKeyEvent(int keycode){
        Instrumentation inst = new Instrumentation();
        inst.sendKeyDownUpSync(keycode);
    }
}

主要的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_as_learning_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.migu.hwj.as.learning.server.AsLearningMainActivity">

    <TextView
        android:id="@+id/tv_receive_msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="接收到的信息:" />

    <TextView
        android:id="@+id/tv_ip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="本机IP地址" />
</LinearLayout>
=== Database Process Memory Monitor (Read-Only, Unit: KB) === Monitors: nvrcore Sample Interval: 5s, Total Samples: 60 Mon Nov 3 20:36:32 UTC 2025 Time | Label | PID VMSZ(KB) RSS(KB) | Free(KB) Buffers(KB) Cached(KB) -------|--------------|-------------------------|---------------------------------- 20:36:32 | INIT | 2730 622700 405148 | 996220 1436 26324 20:36:33 | SAMPLE-1 | 2730 622700 405148 | 996220 1436 26324 20:36:38 | SAMPLE-2 | 2730 622700 405148 | 995700 1436 26320 20:36:43 | SAMPLE-3 | 2730 622700 405148 | 995976 1436 26320 20:36:48 | SAMPLE-4 | 2730 633336 414064 | 987536 1436 26320 20:36:53 | SAMPLE-5 | 2730 633368 414444 | 985732 1436 26364 20:36:58 | SAMPLE-6 | 2730 633400 414288 | 986872 1436 26324 20:37:03 | SAMPLE-7 | 2730 633464 414520 | 986312 1436 26324 20:37:08 | SAMPLE-8 | 2730 633464 414568 | 986484 1436 26372 20:37:13 | SAMPLE-9 | 2730 633464 414568 | 986768 1436 26324 20:37:18 | SAMPLE-10 | 2730 633464 414568 | 985676 1436 26356 20:37:23 | SAMPLE-11 | 2730 633464 414568 | 985736 1436 26324 20:37:28 | SAMPLE-12 | 2730 633464 414568 | 985968 1436 26356 20:37:33 | SAMPLE-13 | 2730 633464 414568 | 986252 1436 26356 20:37:38 | SAMPLE-14 | 2730 633464 414568 | 985980 1436 26324 20:37:43 | SAMPLE-15 | 2730 633464 414568 | 986184 1436 26356 20:37:48 | SAMPLE-16 | 2730 633464 414568 | 986328 1436 26324 20:37:53 | SAMPLE-17 | 2730 633464 414568 | 986328 1436 26356 20:37:58 | SAMPLE-18 | 2730 3454 3457 | 984720 1436 26324 20:38:03 | SAMPLE-19 | 2730 633464 414568 | 985256 1436 26324 20:38:08 | SAMPLE-20 | 2730 633464 414568 | 985572 1436 26356 20:38:13 | SAMPLE-21 | 2730 633464 414568 | 985816 1436 26324 20:38:18 | SAMPLE-22 | 2730 633464 414568 | 985924 1436 26356 20:38:23 | SAMPLE-23 | 2730 633464 414568 | 986532 1436 26324 20:38:28 | SAMPLE-24 | 2730 633464 414568 | 986564 1436 26356 20:38:33 | SAMPLE-25 | 2730 633464 414568 | 986596 1436 26356 20:38:39 | SAMPLE-26 | 2730 633464 414568 | 986744 1436 26324 20:38:44 | SAMPLE-27 | 2730 633464 414568 | 986044 1436 26356 20:38:49 | SAMPLE-28 | 2730 633464 414568 | 985628 1436 26324 20:38:54 | SAMPLE-29 | 2730 633464 414568 | 986012 1436 26356 20:38:59 | SAMPLE-30 | 2730 633464 414568 | 985452 1436 26324 20:39:04 | SAMPLE-31 | 2730 633464 414568 | 986280 1436 26324 20:39:09 | SAMPLE-32 | 2730 633464 414568 | 986144 1436 26356 20:39:14 | SAMPLE-33 | 2730 633464 414568 | 986492 1436 26324 20:39:19 | SAMPLE-34 | 2730 633464 414568 | 985556 1436 26356 20:39:24 | SAMPLE-35 | 2730 633464 414568 | 985988 1436 26324 20:39:29 | SAMPLE-36 | 2730 633464 414568 | 985916 1436 26356 20:39:34 | SAMPLE-37 | 2730 633496 414204 | 986072 1436 26356 20:39:39 | SAMPLE-38 | 2730 633496 414600 | 985752 1436 26324把这个转为便于复制的表格
最新发布
11-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值