UDP实现局域网多人聊天

1.布局

activity_main.xml

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

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:hint="请输入昵称" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="进入聊天室"
        android:textColor="#fff"
        android:background="#2196f3"/>

</LinearLayout>

activity_chat.xml

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

    <RelativeLayout
        android:id="@+id/lts"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#2196f3">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="【聊天室】"
            android:textSize="18dp"
            android:textColor="#fff"
            android:layout_centerInParent="true"/>
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/rl"
        android:layout_below="@id/lts"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#90caf9">
        <TextView
            android:id="@+id/tv"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:layout_weight="7"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center"
            android:marqueeRepeatLimit="marquee_forever"
            android:singleLine="true"
            android:text="还在等什么,分享软件邀请小伙伴加入局域网一起来侃大山吧………………"
            android:textColor="#fff" />
        <ImageView
            android:id="@+id/iv"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:src="@android:drawable/ic_menu_close_clear_cancel"
            android:layout_weight="1"/>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#fafafa"
        android:layout_alignParentBottom="true">
        <EditText
            android:id="@+id/send_et"
            android:layout_width="200dp"
            android:layout_height="40dp"
            android:layout_weight="4.5"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"/>

        <Button
            android:id="@+id/send_btn"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="3dp"
            android:layout_marginRight="5dp"
            android:layout_marginTop="5dp"
            android:layout_weight="0.5"
            android:background="#2196f3"
            android:text="  发送  "
            android:textColor="#fff" />
    </LinearLayout>

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/ll"
        android:layout_below="@id/rl"
        android:transcriptMode="alwaysScroll"/>

</RelativeLayout>

ListView的子布局receive_mode.xml

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/img_receive"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@mipmap/ic_launcher"/>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_weight="1"
            android:orientation="vertical">
            <TextView
                android:id="@+id/person_receive"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:layout_marginTop="5dp"
                android:text="对方"
                android:textColor="#1e88e5"
                android:textSize="14dp" />
            <TextView
                android:id="@+id/content_receive"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_toRightOf="@+id/ll"
                android:layout_marginTop="5dp"
                android:text="测试内容"
                android:textColor="#000"
                android:textSize="20dp"
                android:background="#2196f3"/>
        </LinearLayout>
        <TextView
            android:layout_width="50dp"
            android:layout_height="wrap_content" />
    </LinearLayout>
</RelativeLayout>

send_mode.xml

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="50dp"
            android:layout_height="wrap_content" />
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginRight="5dp"
            android:gravity="right"
            android:layout_weight="1">
            <TextView
                android:id="@+id/chat_person_send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:text="自己"
                android:textSize="14dp"
                android:textColor="#1e88e5"/>
            <TextView
                android:id="@+id/chat_content_send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_marginTop="5dp"
                android:layout_toLeftOf="@+id/l"
                android:layout_toStartOf="@+id/l"
                android:text="测试内容"
                android:textColor="#000"
                android:textSize="20dp"
                android:background="#2196f3"/>
        </LinearLayout>

        <ImageView
            android:id="@+id/img_send"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:src="@mipmap/ic_launcher" />

        </LinearLayout>
</RelativeLayout>

2.Activity

MainActivity 

package com.cwj.chat;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button adminBtn;
    private RadioButton male,female;
    private EditText nameEt;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        adminBtn = (Button) findViewById(R.id.btn_login);
        nameEt = (EditText) findViewById(R.id.editText1);

        adminBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch(view.getId()){
            case R.id.btn_login:
                if(nameEt.length() == 0){
                    DisplayToast("昵称不能为空!");
                    return;
                }
                else if(nameEt.length()>10){
                    DisplayToast("建议昵称不超过10个字节");
                    return;
                }
                Intent intent = new Intent(this,ChatActivity.class);
                intent.putExtra("name",nameEt.getText().toString());
                startActivity(intent);
                break;
            default:
                break;
        }
    }

    //自定义Toast
    private void DisplayToast(String str){
        Toast toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);
        toast.setGravity(Gravity.BOTTOM, 0, 220);
        toast.show();
    }

}

package com.svse.sobbs.activity;

import android.os.Bundle;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.svse.sobbs.chatclass.Constant;
import com.svse.sobbs.chatclass.Request;
import com.svse.sobbs.chatclass.RequestDecode;
import com.svse.sobbs.chatclass.Response;
import com.svse.sobbs.R;

public class ChatActivity extends BaseActivity implements View.OnClickListener{

    private ListView myListView ;
    private String str;
    private EditText sendMsg;
    private Button sendBtn;
    private MyAdapter adapter;
    List<Map<String, String>> data ;
    Map<String,String> map,map1 ;
    private ImageView iv,ivbj;
    private LinearLayout rl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        receiveListen();
        initView();
        Intent intent = getIntent();
        str = intent.getStringExtra("name");
    }

    @Override
    protected int getLayoutID() {
        return R.layout.activity_chat;
    }

    protected void  initView() {
        data = new ArrayList<Map<String,String>>();
        sendMsg = (EditText)findViewById(R.id.send_et);
        sendBtn = (Button)findViewById(R.id.send_btn);
        adapter = new MyAdapter(this);
        myListView = (ListView)findViewById(R.id.listView1);
        myListView.setSelection(myListView.getBottom());
        myListView.setAdapter(adapter);

        iv = (ImageView) findViewById(R.id.iv);
        rl = (LinearLayout) findViewById(R.id.rl);
        //隐藏提示内容的布局
        iv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if(rl.getVisibility() == View.VISIBLE){
                    //隐藏
                    rl.setVisibility(View.GONE);
                }else {
                    //可见
                    rl.setVisibility(View.VISIBLE);
                }
            }
        });

        sendBtn.setOnClickListener(this);
    }

    @Override
    protected void initListener() {

    }
    private void receiveListen() {
        Thread thread = new Thread(new Listener(8080));
        thread.start();
    }

    @Override
    protected void initData() {

    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            //点击发送按钮
            case R.id.send_btn:
                doSendButton();
                break;
        }

    }
    private void doSendButton() {
        if(sendMsg.length() == 0){
            //判断发送消息是否为空
            DisplayToast("发送消息不能为空!");
            return;
        }
        else {
            //不为空发送传过来的昵称和编辑框的消息
            map = new HashMap<String, String>();
            map.put("myName", str);
            map.put("myMsg", sendMsg.getText().toString());
            data.add(map);
            Thread thread = new Thread(new sendMsg(map));
            thread.start();
        }
        Message msg = new Message();
        msg.what = 1;
        myHandler.sendMessage(msg);
        sendMsg.setText("");
    }

    private void DisplayToast(String str){
        Toast toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);
        toast.setGravity(Gravity.BOTTOM, 0, 220);
        toast.show();
    }

    Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 1){
                if(sex.equals("male")){
                    adapter.mySex = true;
                }else{
                    adapter.mySex = false;
                }
                adapter.count++;
                adapter.notifyDataSetChanged();
                return;
            }
            else if(msg.what == 0){
                adapter.count++;
                adapter.notifyDataSetChanged();
                return;
            }
        }

    };

    class sendMsg implements Runnable {
        Request myRequest = new Request();
        Map<String,String> map ;

        public sendMsg(Map<String,String> map) {
            this.map = map;
        }
        @Override
        public void run() {
            try {
                myRequest.send(Constant.MESSAGE+";"+map.get("myName")+";"+";"+map.get("myMsg")+";!",
                        InetAddress.getByName("255.255.255.255"), 8080);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
    }

    class Listener implements Runnable{

        private Response myResponse;
        private RequestDecode myDecode;
        private int port;//监听端口
        private boolean flag =true;//循环标志
        public Listener(int port){
            this.port = port;
        }
        /**
         * 循环接收port端口的请求
         */
        @Override
        public void run() {
            while(flag){
                initData();
                try {
                    myResponse.receive(port);
                    myDecode.decode(myResponse.data);
                    responseRun(myDecode.response);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        private void responseRun(ArrayList<String> response) throws IOException, InterruptedException {
            if(response.get(0).equals(Constant.MESSAGE)&&!response.get(1).equals(str)){
                map1 = new HashMap<String, String>();
                map1.put("otherName", response.get(1));
                map1.put("otherSex", response.get(2));
                map1.put("otherMsg", response.get(3));
                data.add(map1);
                Message msg = new Message();
                msg.what = 0;
                myHandler.sendMessage(msg);
            }
        }
        private void initData() {
            myDecode = new RequestDecode();
            myResponse = new Response();
        }

    }
    class MyAdapter extends BaseAdapter{
        private LayoutInflater mInflater = null;
        private boolean mySex = true;
        int count = 0;
        public MyAdapter(Context context) {
            this.mInflater = LayoutInflater.from(context);
        }
        @Override
        public int getCount() {
            return count;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }
        @Override
        public boolean areAllItemsEnabled() {
            return false;
        }

        @Override
        public boolean isEnabled(int position) {
            return false;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if(data.get(position).get("myName") != null){
                //加载自己消息的布局
                convertView = LayoutInflater.from(getApplicationContext()).inflate(
                        R.layout.send_mode, null);
                holder = new ViewHolder();
                holder.name = (TextView)convertView.findViewById(R.id.chat_person_send);
                holder.content = (TextView) convertView.findViewById(R.id.chat_content_send);
                holder.person = (ImageView)convertView.findViewById(R.id.img_send);
                convertView.setTag(holder);
                if(mySex){
                    //显示发送人头像
                   holder.person.setImageResource(R.drawable.icon_find);
                }else{
                    holder.person.setImageResource(R.drawable.icon_find);
                }
                holder.name.setText(data.get(position).get("myName"));
                holder.content.setText(data.get(position).get("myMsg"));
            }
            else{
                //加载对方消息的布局
                convertView = LayoutInflater.from(getApplicationContext()).inflate(
                        R.layout.receive_mode, null);
                holder = new ViewHolder();
                holder.name = (TextView)convertView.findViewById(R.id.person_receive);
                holder.content = (TextView) convertView.findViewById(R.id.content_receive);
                holder.person = (ImageView)convertView.findViewById(R.id.img_receive);
                convertView.setTag(holder);
                if(data.get(position).get("otherSex").equals("male")){
                    //显示对方头像
                    holder.person.setImageResource(R.drawable.icon_find_un);
                }else{
                    holder.person.setImageResource(R.drawable.icon_find_un);
                }
                holder.name.setText(data.get(position).get("otherName"));
                holder.content.setText(data.get(position).get("otherMsg"));
            }
            return convertView;
        }

    }
    @Override
    public void onBackPressed() {
        leave();
    }

    /**
     * 弹窗退出聊天室
     */
    public void leave()
    {
        AlertDialog.Builder dialog=new AlertDialog.Builder(ChatActivity.this);
        dialog.setTitle("您真的要退出聊天室吗?").setPositiveButton("退出", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
               finish();
            }
        }).setNegativeButton("取消", new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();//取消弹出框
            }
        }).create().show();
    }

    /**存放控件*/
    public final class ViewHolder{
        private TextView name;
        private ImageView person;
        private TextView content;
    }
}

3.其他类

package com.cwj.chat.chatclass;

/**
 * Created by 17551_000 on 2017/9/4.
 */

public class Constant {

        public static final String MESSAGE = "Message"  ;

}

发送请求

package com.cwj.chat.chatclass;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * Created by 17551_000 on 2017/9/4.
 */

public class Request {
    /**
     * 发送函数  :参数为 所发命令command,目的ip地址,使用端口号port。
     * @param command
     * @param ip
     * @param port
     * @throws UnsupportedEncodingException
     * @throws SocketException
     * @throws IOException
     */
    public void send(String command, InetAddress ip, int port) throws UnsupportedEncodingException, SocketException {
        // UDP的发送
        DatagramPacket dp = new DatagramPacket(command.getBytes("UTF-8"),
                command.getBytes("UTF-8").length, ip, port);
        System.out.println(ip);
        DatagramSocket ds = new DatagramSocket();
        //新建一个线程
        Thread t = new Thread(new RequestRunnable(dp,ds));
        //开启线程
        t.start();

        System.out.println("-->端口 "+port+" 发送命令:"+command);
    }

}


package com.cwj.chat.chatclass;

import java.util.ArrayList;

/**
 * Created by 17551_000 on 2017/9/4.
 */

public class RequestDecode {

    public String content ;
    public ArrayList<String> response = new ArrayList<String>();
    public static final char ENDCOMMAND = '!';
    public static final char NODECOMMAND = ';';
    public void decode(String data) throws Exception {
        int beginIndex = 0;
        int endIndex = 0;
        while(endIndex <= data.length() && data.charAt(endIndex) != ENDCOMMAND){
            if(data.charAt(endIndex) == NODECOMMAND){
                content = data.substring(beginIndex, endIndex);
                System.out.println("content="+content);
                response.add(content);
                beginIndex = endIndex+1;
            }
            endIndex++;
        }
        System.out.println("response = "+response);
    }

}

package com.cwj.chat.chatclass;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * Created by 17551_000 on 2017/9/4.
 */
class RequestRunnable implements Runnable {
    DatagramPacket dp;
    DatagramSocket ds;
    //DatagramPacket数据包,DatagramSocket数据包套接字
    public RequestRunnable(DatagramPacket dp, DatagramSocket ds){
        this.dp = dp;
        this.ds = ds;
    }
    @Override
    public void run() {
        try {
            ds.send(dp);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ds.close();
    }

}

接收消息

package com.cwj.chat.chatclass;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * Created by 17551_000 on 2017/9/4.
 */

public class Response {

    public InetAddress ip = null;
    public String data;
    /**
     * 接收函数 :开启所传参数端口的接收端
     * @param port
     * @throws IOException
     */
    public void receive(int port) throws IOException {
        System.out.println("-->开启接收端口:"+port);
        //UDP的接收码
        DatagramSocket ds = new DatagramSocket(port);
        byte[] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf, buf.length);
        ds.receive(dp);
        ip = dp.getAddress();
        data = new String(dp.getData(),0,dp.getLength(),"UTF-8");
        ds.close();
        System.out.println("-->ip:"+ip+"\n-->内容:"+data);
        System.out.println("-->端口"+port+":  接收成功");
    }

}

权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

举儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值