UDP通信简单 小结

Android手机版和电脑版 效果图: 通过WiFi局域网 电脑和手机连接通信. 电脑版本和手机版本使用了相同的消息发送头协议, 可以相互接收消息. 若有做的不好的地方还希望大家指导一下.

1. 手机版

添加权限 AndroidManifest.xml

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
View Code

页面 activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <EditText
                android:id="@+id/editText1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:ems="10" >

                <requestFocus />
            </EditText>

            <Button
                android:id="@+id/button1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="连接" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <EditText
                android:id="@+id/editText2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:ems="10" />

            <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="发送" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Large Text"
                android:textAppearance="?android:attr/textAppearanceLarge" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >

            <ScrollView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:fadingEdge="vertical"
                android:scrollbars="vertical" >

                <TextView
                    android:id="@+id/textView2"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="Large Text"/>
            </ScrollView>
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>
View Code

后台代码 MainActivity.java

package com.example.udppacket;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.Window;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.java.net.IPUtils;
import com.java.net.MessageEntity;
import com.java.net.UdpEntitiy;
import com.java.net.UdpEntitiy.ReceivesListener;

public class MainActivity extends ActionBarActivity {

    EditText ip;
    EditText send;
    TextView txt;
    TextView msgs;

    UdpEntitiy udp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        this.requestWindowFeature(Window.FEATURE_NO_TITLE);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ip = (EditText) findViewById(R.id.editText1);
        send = (EditText) findViewById(R.id.editText2);
        txt = (TextView) findViewById(R.id.textView1);
        msgs = (TextView) findViewById(R.id.textView2);

        send.setText("Hello Word!");
        txt.setText("");
        msgs.setText("");
        ip.setText(IPUtils.getHostIP());

        udp = UdpEntitiy.getUdpEntitiy();

        /**
         * 监听消息
         * */
        udp.onReceiveMessage(new ReceivesListener() {

            @Override
            public void onReceiveMessage(MessageEntity messageEntity) {
                // TODO Auto-generated method stub

                Message msg = new Message();
                msg.obj = messageEntity;
                msgHd.sendMessage(msg);
            }
        });
        // 连接
        findViewById(R.id.button1).setOnClickListener(
                new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        if (!udp.isReceive()) {
                            udp.startReceive();
                            Toast.makeText(MainActivity.this, "已连接!", Toast.LENGTH_SHORT).show();
                        }else {
                            udp.stopReceive();
                            Toast.makeText(MainActivity.this, "已关闭!", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
        // 发送
        findViewById(R.id.button2).setOnClickListener(
                new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        if (!send.getText().toString().equals("")) {
                            udp.send(ip.getText().toString(), send.getText().toString());
                            msgs.append("我 : " + send.getText().toString() + "
");
                            send.setText("");
                        }else {
                            Toast.makeText(MainActivity.this, "请输入消息!", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }

    Handler msgHd = new Handler() {

        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            MessageEntity me = (MessageEntity) msg.obj;
            if (me.type.equals("00")) {// 文字
                msgs.append("来自 [ " + me.sendIP + " ] :" + me.getString() + "
");

            }
        };
    };

}
View Code

以下是类库代码:

获取IP地址 IPUtils.java 可要可不要

package com.java.net;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;

public class IPUtils {

    /***
     * 
     * <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     * /
    /**
     * 获取ip地址
     * @return
     */
    public static String getHostIP() {

        String hostIp = null;
        try {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            InetAddress ia = null;
            while (nis.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration<InetAddress> ias = ni.getInetAddresses();
                while (ias.hasMoreElements()) {
                    ia = ias.nextElement();
                    if (ia instanceof Inet6Address) {
                        continue;// skip ipv6
                    }
                    String ip = ia.getHostAddress();
                    if (!"127.0.0.1".equals(ip)) {
                        hostIp = ia.getHostAddress();
                        break;
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return hostIp;

    }


    /*
     **
     * 获取本机IPv4地址
     *
     * @param context
     * @return 本机IPv4地址;null:无网络连接
     */
    public static String getIpAddress(Context context) {
        // 获取WiFi服务
        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        // 判断WiFi是否开启
        if (wifiManager.isWifiEnabled()) {
            // 已经开启了WiFi
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            int ipAddress = wifiInfo.getIpAddress();
            String ip = intToIp(ipAddress);
            return ip;
        } else {
            // 未开启WiFi
            return getIpAddress();
        }
    }

    private static String intToIp(int ipAddress) {
        return (ipAddress & 0xFF) + "." +
                ((ipAddress >> 8) & 0xFF) + "." +
                ((ipAddress >> 16) & 0xFF) + "." +
                (ipAddress >> 24 & 0xFF);
    }

    /**
     * 获取本机IPv4地址
     *
     * @return 本机IPv4地址;null:无网络连接
     */
    private static String getIpAddress() {
        try {
            NetworkInterface networkInterface;
            InetAddress inetAddress;
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                networkInterface = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = networkInterface.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                    inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {
                        return inetAddress.getHostAddress();
                    }
                }
            }
            return null;
        } catch (SocketException ex) {
            ex.printStackTrace();
            return null;
        }
    }

}
View Code

发送接收消息包装类库 :MessageEntity.java

package com.java.net;

import java.io.ByteArrayOutputStream;
import java.io.File;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

/**
 * 标识 000000, 6位 类型00... , 00 :字符串, 01 :图片, 02 :文件 ... 2位(不足使用字母代替) 是否接收确认0 - 1
 * , 0 :不确认 ,1 :确认 1位 默认不确认0 是否为最后一个 0 - 1, 0 :不是最后一个, 1 :最后一个 1位 默认最后一个1
 * 数据byte[]
 * */
public class MessageEntity {
    // 初始化
    private void init() {
        flagNo = getRandom();// 6 位随机数
        type = "00";
        isPass = "0";
        isLast = "1";
    }

    public MessageEntity() {
        init();
    }
    public MessageEntity(String s){
        init();
        type = "00";//字符串
        datas = s.getBytes();
    }
    public MessageEntity(File s){
        init();
        type = "02";//文件
        //文件流转换
    }
    public MessageEntity(Bitmap s){
        init();
        type = "01";//Bitmap  图片
        datas = Bitmap2Bytes(s);
    }
    //根据字节获取图片
    public Bitmap getBitmap(){
        if (datas != null && datas.length > 0) {
            return Bytes2Bimap(datas);
        }
        return null;
    }
    //根据字节获取字符串
    public String getString(){
        if (datas != null && datas.length > 0) {
            return new String(datas, 0, datas.length);
        }
        return null;
    }
    //根据字节获取文件
    public String getFile(){
        if (datas != null && datas.length > 0) {
            //代码
            return null;
        }
        return null;
    }
    //获取头字节
    public byte[] getHeadToByte(){
        return (getFlagNo() + "," + type + "," + isPass + "," + isLast).getBytes();
    }
    //根据字节 重置头部参数
    public MessageEntity resetParameter(byte[] b, MessageEntity m){
        if (m == null) {
            m = new MessageEntity();
        }
        if (b != null && b.length > 0) {
            String s = new String(b, 0, b.length);
            resetParameter(s,m);
        }
        return m;
    }
    //根据字节 重置头部参数
    public MessageEntity resetParameter(String b, MessageEntity m){
        String[] ss = b.split(",");
        if (ss.length >= 4) {
            m.flagNo = ss[0];
            m.type = ss[1];
            m.isPass = ss[2];
            m.isLast = ss[3];
        }
        return m;
    }
    private String flagNo;// 消息编号
    public String getFlagNo(){
        return flagNo;
    }
    public String type;// 消息类型
    public String isPass;// 是否确认
    public String isLast;// 是否为最后一条
    public boolean isReader;//消息是否已读
    public byte[] datas;// 数据字节
    public String sendIP;// 发送方 IP
    public int sendPort;// 发送方 端口
    // 字节转为为图片
    private Bitmap Bytes2Bimap(byte[] b) {
        if (b.length != 0) {
            return BitmapFactory.decodeByteArray(b, 0, b.length);
        } else {
            return null;
        }
    }
    // 将图片转为字节
    private byte[] Bitmap2Bytes(Bitmap bm) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
        return baos.toByteArray();
    }
    //产生随机数并凑够6位
    private String getRandom() {
        int r = (int) (Math.random() * 1000000);
        String a = Integer.toString(r);
        return getFormatString(a, 6);
    }
    private String getFormatString(String s, int n) {
        n = n - s.length();
        for (int i = 0; i < n; i++) {
            s = "0" + s;// 为了凑够6位数
        }
        return s;
    }
}
View Code

管理消息类(主要是针对发送消息过大,分批发送使用) : MessageManage.java

package com.java.net;

import java.util.ArrayList;
import java.util.List;

/**
 * 消息管理
 * */
public class MessageManage {

    private MessageManage(){
        list = new ArrayList<MessageEntity>();
    }
    private static MessageManage msgm = new MessageManage();
    public static MessageManage getMessageManage(){
        return msgm;
    }
    private static List<MessageEntity> list;
    //添加
    public void add(MessageEntity me){
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                MessageEntity dd = list.get(i);
                if (dd.getFlagNo().equals(me.getFlagNo())) {
                    dd.datas = addBytes(dd.datas,me.datas);
                    return;
                }
            }
        }
        //新添加时, 如果数量大于 max则移除所有
        if (size()>MaxSize) {
            for (int i = 0; i < list.size(); i++) {
                MessageEntity dd = list.get(i);
                if (dd.isReader) {
                    list.remove(i);//移除已读消息
                }
            }
        }
        list.add(me);
    }
    final int MaxSize = 500;//如果大于500条则自动清理
    //读取消息
    public MessageEntity reader(MessageEntity me){
        for (int i = 0; i < list.size(); i++) {
            MessageEntity dd = list.get(i);
            if (dd.getFlagNo().equals(me.getFlagNo())) {
                //设置为已读
                dd.isReader = true;
                return dd;
            }
        }
        return null;
    }
    public static int size(){
        return list.size();
    }
    //合并两个字节数组
    public static byte[] addBytes(byte[] data1, byte[] data2) {
        byte[] data3 = new byte[data1.length + data2.length];
        System.arraycopy(data1, 0, data3, 0, data1.length);
        System.arraycopy(data2, 0, data3, data1.length, data2.length);
        return data3;

    }
}
View Code

UDP端口发送监听类 UdpEntitiy.java 用于发送消息和监听消息

package com.java.net;

import java.io.File;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import android.graphics.Bitmap;
import android.os.Message;


public class UdpEntitiy{

    private UdpEntitiy(){
    }
    private static UdpEntitiy udp = new UdpEntitiy();
    public static UdpEntitiy getUdpEntitiy(){
        return udp;
    }
    private int port = 12345;//监听端口
    private int getPortSend() {//临时端口 发送时使用
        return (port + 1);
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }
    private boolean isReceive;//是否监听
    public boolean isReceive() {
        return isReceive;
    }
    public void startReceive(){
        if (!isReceive) {//如果没有监听
            new Thread(){
                public void run() {
                    receiveMessage();
                };
            }.start();
        }
    }
    //发送消息
    public void send(final String ip,final MessageEntity ms){
        new Thread(){
            public void run() {
                sendMessage(ip,ms);
            };
        }.start();
    }
    //发送文字
    public void send(final String ip,String s){
        final MessageEntity ms = new MessageEntity(s);
        send(ip,ms);
    }
    //发送图片
    public void send(final String ip,Bitmap s){
        final MessageEntity ms = new MessageEntity(s);
        send(ip,ms);
    }
    //发送文件
    public void send(final String ip,File s){
        final MessageEntity ms = new MessageEntity(s);
        send(ip,ms);
    }
    public void stopReceive(){
        if (isReceive) {//如果监听
            socket.close();
        }
    }
    //接收消息接口
    public interface ReceivesListener extends EventListener{
        //当接收到消息时
        public void onReceiveMessage(MessageEntity messageEntity);
    }
    private Collection listeners = new HashSet();
    public void onReceiveMessage(ReceivesListener receiveListener){
        if (listeners == null) {
            listeners = new HashSet();
        }
        listeners.add(receiveListener);
    }
    private void notifyListener(MessageEntity s){
        if (listeners != null) {
            Iterator iter = listeners.iterator();
            while (iter.hasNext()) {
                ReceivesListener r = (ReceivesListener) iter.next();
                r.onReceiveMessage(s);
            }
        }
    }
    
    DatagramSocket socket = null;//声明 数据报套接字
    final int VALUE_MAX = 2048;//接收发送最大字节 2kb
    LinkedList flags = new LinkedList();
    MessageManage msgm = MessageManage.getMessageManage();
    //监听数据接收
    private void receiveMessage(){
        try {
            socket = new  DatagramSocket(port);//初始化 数据报套接字
            isReceive = true;//设置状态 - 已经在监听
            while (true) {
                byte data[] = new byte[VALUE_MAX];//接收存放的字节
                DatagramPacket packet = new DatagramPacket(data, data.length);//声明初始化接收的数据包
                //阻塞监听
                socket.receive(packet);
                //接收到端口数据消息
                MessageEntity me = new MessageEntity();
                //截获返回符
                if (packet.getLength() == me.getFlagNo().length()) {
                    flags.add(new String(packet.getData(),packet.getOffset(),packet.getLength()));
                    continue;
                }
                me.sendIP = packet.getAddress().getHostAddress();
                me.sendPort = packet.getPort();
                //设置头部信息
                int headSize = me.getHeadToByte().length;
                me.resetParameter(new String(packet.getData(),packet.getOffset(),headSize), me);
                //获取有效字节
                byte ndata[] = new byte[packet.getLength()-headSize];
                System.arraycopy(packet.getData(),headSize,ndata,0,ndata.length);
                me.datas = ndata;//赋值
                //添加到消息中
                msgm.add(me);
                if (me.isLast.equals("1")) {//最后一个
                    me = msgm.reader(me);
                    notifyListener(me);//通知
                }
            }
        } catch (SocketException e) {
            //socket 关闭是会抛异常, 才可以停止消息阻塞
        } catch (IOException e) {
        }finally{
            isReceive = false;
            if (socket!=null) {
                socket.close();
            }
        }
    }

    //发送
    private void sendMessage(String ip, MessageEntity ms){
        DatagramSocket ssocket = null;//声明 发送套接字
        try {
            ms.isLast = "1";//先设置为最后一个
            byte[] hd1 = ms.getHeadToByte();//已完成的头部字节
            ssocket = new  DatagramSocket (getPortSend());//初始化 发送套接字 使用临时端口
            InetAddress serverAddress = InetAddress.getByName(ip);//声明初始化 服务器地址
            //发消息是否有返回确认
            if (ms.isPass.equals("1")) {//需要确认
                //发送确认码
                byte[] qrm = ms.getFlagNo().getBytes();
                DatagramPacket packet = new DatagramPacket(qrm, qrm.length, serverAddress, port);
                ssocket.send(packet);
                boolean qm = true;
                while(qm){
                    if (flags.size() > 0) {
                        for (int i = 0; i < flags.size(); i++) {
                            if (flags.get(i).equals(ms.getFlagNo())) {
                                flags.remove(i);
                                qm = false;
                                break;
                            }
                        }
                    }
                }
            }
            int allLength = ms.datas.length + hd1.length;
            if (allLength <= VALUE_MAX) {//一次发送
                byte[] sbt = addBytes(hd1,ms.datas);
                //声明初始化 数据发送包 端口为 服务器监听端口
                DatagramPacket packet = new DatagramPacket(sbt, sbt.length, serverAddress, port);
                //发送
                ssocket.send(packet);
            }else {//分次发送
                //int n = allLength / (VALUE_MAX - hd1.length);
                //int m = allLength % (VALUE_MAX - hd1.length);
                //n = n + (m > 0 ? 1 : 0);
                byte[] hd2 = ms.getHeadToByte();//未完成的头部字节
                int n = ms.datas.length / VALUE_MAX;
                int d = ms.datas.length % VALUE_MAX;
                int m = n * hd2.length;
                int c = (m + d) / VALUE_MAX;
                int f = (m + d) % VALUE_MAX;
                n = n + c + (f > 0 ? 1 : 0);
                ms.isLast = "0";
                for (int i = 0; i < n; i++) {
                    if (i == (n - 1)) {
                        byte[] nbt = new byte[m];
                        System.arraycopy(ms.datas, i * (VALUE_MAX-hd2.length), nbt, 0, nbt.length);
                        byte[] dt1 = addBytes(hd1,nbt);//未完成状态 和 字节之和
                        DatagramPacket packet = new DatagramPacket(dt1, dt1.length, serverAddress, port);
                        ssocket.send(packet);
                    }else {
                        byte[] nbt = new byte[VALUE_MAX-hd2.length];
                        System.arraycopy(ms.datas, i * (VALUE_MAX-hd2.length), nbt, 0, nbt.length);
                        byte[] dt1 = addBytes(hd2,nbt);//未完成状态 和 字节之和
                        DatagramPacket packet = new DatagramPacket(dt1, dt1.length, serverAddress, port);
                        ssocket.send(packet);
                    }
                }
            }
        } catch (SocketException e) {
        } catch (IOException e) {
        }finally{
            if (ssocket!=null) {
                ssocket.close();//关闭
            }
        }
    }
    //合并字节数组
    private static byte[] addBytes(byte[] data1, byte[] data2) {
        byte[] data3 = new byte[data1.length + data2.length];
        System.arraycopy(data1, 0, data3, 0, data1.length);
        System.arraycopy(data2, 0, data3, data1.length, data2.length);
        return data3;
    }
}
View Code

以上是所有代码,  最简单的调用如下  实现发送接收

        UdpEntitiy udp = UdpEntitiy.getUdpEntitiy();//获取
        udp.startReceive();//开始监听
        /**
         * 监听消息
         * 当收到消息时调用
         * */
        udp.onReceiveMessage(new ReceivesListener() {

            @Override
            public void onReceiveMessage(MessageEntity messageEntity) {
                // TODO Auto-generated method stub
                Message msg = new Message();
                msg.obj = messageEntity;
                msgHd.sendMessage(msg);
            }
        });
        /**
         * 发送消息
         * 第一个是要发送到的IP, 第二个是消息
         * */
        udp.send(ip.getText().toString(), send.getText().toString());
View Code

2. 电脑版本 c#

当类库写完之后最简单的调用如下:

//放在窗体初始化上面
UdpSocket.OnListenter += recive;
InitializeComponent();//初始控件


//加载事件
UdpSocket.Start();//开启监听[线程]

//窗体关闭事件
UdpSocket.Close();//关闭监听[线程]

//发送消息
UdpSocket.SendMessage("目标IP地址", "消息");

//定义接收消息的方法
private void recive(MessageEntity msg) 
{
    //消息封装在了MessageEntity中
    //通过 msg.GetString() 获取消息
}
View Code

以下是全部代码:

窗体初始化控件代码自动生成的

namespace UdpEntity
{
    partial class Form1
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗体设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.textBox2 = new System.Windows.Forms.TextBox();
            this.textBox3 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(378, 303);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(75, 23);
            this.button1.TabIndex = 0;
            this.button1.TabStop = false;
            this.button1.Text = "发送";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click_1);
            // 
            // textBox1
            // 
            this.textBox1.BackColor = System.Drawing.Color.White;
            this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.ReadOnly = true;
            this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.textBox1.Size = new System.Drawing.Size(441, 280);
            this.textBox1.TabIndex = 1;
            this.textBox1.TabStop = false;
            // 
            // textBox2
            // 
            this.textBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.textBox2.Location = new System.Drawing.Point(12, 303);
            this.textBox2.Name = "textBox2";
            this.textBox2.Size = new System.Drawing.Size(360, 21);
            this.textBox2.TabIndex = 2;
            this.textBox2.TabStop = false;
            // 
            // textBox3
            // 
            this.textBox3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.textBox3.Location = new System.Drawing.Point(12, 337);
            this.textBox3.Multiline = true;
            this.textBox3.Name = "textBox3";
            this.textBox3.Size = new System.Drawing.Size(441, 121);
            this.textBox3.TabIndex = 3;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(472, 469);
            this.Controls.Add(this.textBox3);
            this.Controls.Add(this.textBox2);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "Form1";
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "局域网聊天";
            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Form1_FormClosed);
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.TextBox textBox2;
        private System.Windows.Forms.TextBox textBox3;

    }
}
View Code

窗体后台代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Diagnostics;

namespace UdpEntity
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            UdpSocket.OnListenter += recive;
            InitializeComponent();
        }

       

        private void Form1_Load(object sender, EventArgs e)
        {
            UdpSocket.Start();
            textBox2.Text = "192.168.1.103";
        }

        private void recive(MessageEntity msg) 
        {
            textBox1.AppendText("
消息来自: [ " + msg.sendIp + " ]
" + msg.GetString());
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            UdpSocket.Close();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            if (textBox2.Text != "" && textBox3.Text != "")
            {
                UdpSocket.SendMessage(textBox2.Text, textBox3.Text);
                textBox3.Text = "";
            }
        }
    }
}
View Code

封装的接收消息类库 MessageEntity.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UdpEntity
{
    public class MessageEntity
    {
        #region 字段
        private string flagNo;
        /// <summary>
        /// 获取消息标识
        /// </summary>
        /// <returns></returns>
        public string GetFlagNo()
        {
            return flagNo;
        }
        /// <summary>
        /// 发送接收 数据类型
        /// </summary>
        public string type;
        /// <summary>
        /// 是否有返回
        /// </summary>
        public string isPass;
        /// <summary>
        /// 是否为最后一条消息
        /// </summary>
        public string isLast;
        /// <summary>
        /// 是否已读
        /// </summary>
        public bool isReader;
        /// <summary>
        /// 发送方IP
        /// </summary>
        public string sendIp;
        /// <summary>
        /// 发送方端口
        /// </summary>
        public int sendPort;
        /// <summary>
        /// 存放的数据
        /// </summary>
        public byte[] datas;
        
        #endregion

        #region 方法
        
        public MessageEntity()
        {
            init();
        }
        //初始化
        private void init()
        {
            flagNo = getRandom();//getRandom();// 6 位随机数
            type = "00";
            isPass = "0";
            isLast = "1";
        }
        public MessageEntity(string s)
        {
            init();
            type = "00";//字符串
            datas = Encoding.GetEncoding("UTF-8").GetBytes(s);
        }
        //根据字节获取字符串
        public string GetString()
        {
            if (datas != null && datas.Length > 0)
            {
                return Encoding.GetEncoding("UTF-8").GetString(datas, 0, datas.Length);
            }
            return string.Empty;
        }
        //获取头字节
        public byte[] getHeadToByte()
        {
            return Encoding.GetEncoding("UTF-8").GetBytes((GetFlagNo() + "," + type + "," + isPass + "," + isLast));
        }
        //根据字节 重置头部参数
        public MessageEntity resetParameter(byte[] b, MessageEntity m)
        {
            if (m == null)
            {
                m = new MessageEntity();
            }
            if (b != null && b.Length > 0)
            {
                string s = Encoding.GetEncoding("UTF-8").GetString(b, 0, b.Length);
                resetParameter(s, m);
            }
            return m;
        }
        //根据字节 重置头部参数
        public MessageEntity resetParameter(string b, MessageEntity m)
        {
            string[] ss = b.Split(',');
            if (ss.Length >= 4)
            {
                m.flagNo = ss[0];
                m.type = ss[1];
                m.isPass = ss[2];
                m.isLast = ss[3];
            }
            return m;
        }
        //产生随机数并凑够6位
        public String getRandom()
        {
            string aa = (Math.Abs(Guid.NewGuid().GetHashCode()) % 1000000).ToString();
            return getFormatString(aa, 6);
        }
        private String getFormatString(string s, int n)
        {
            n = n - s.Length;
            for (int i = 0; i < n; i++)
            {
                s = "0" + s;// 为了凑够6位数
            }
            return s;
        }
        #endregion
    }
}
View Code

消息管理类库 MessageManage.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UdpEntity
{
    public class MessageManage
    {
        private MessageManage() { }
        private static MessageManage msgm = new MessageManage();
        public static MessageManage GetMessageManange()
        {
            return msgm;
        }
        List<MessageEntity> list = new List<MessageEntity>();
        int MaxSize = 500;//如果大于500条则自动清理
        //Buffer.BlockCopy(dst, 0, cc, src.Length, dst.Length);
        //Buffer.BlockCopy([源数组], [从源数组哪里开始, 偏移量], 
        // [目标数组] , [从目标数组哪里开始, 偏移量] , [所要复制的字节大小, 长度]);
        public byte[] CopyByte(byte[] src, byte[] dst)
        {
            byte[] cc = new byte[src.Length + dst.Length];
            Buffer.BlockCopy(src, 0, cc, 0, src.Length);
            Buffer.BlockCopy(dst, 0, cc, src.Length, dst.Length);
            return cc;
        }
        public void Add(MessageEntity me)
        {
            if (list.Count > 0)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    MessageEntity m = list[i];
                    if (m.GetFlagNo() == me.GetFlagNo())
                    {
                        byte[] a = new byte[1];
                        byte[] b = new byte[1];
                        me.datas = CopyByte(a, b);
                        return;
                    }
                }
            }
            //新添加时, 如果数量大于 max则移除所有
            if (size() > MaxSize)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    MessageEntity dd = list[i];
                    if (dd.isReader)
                    {
                        list.RemoveAt(i);//移除已读消息
                    }
                }
            }
            list.Add(me);

        }
        public int size()
        {
            return list.Count;
        }
        //读取消息
        public MessageEntity reader(MessageEntity me)
        {
            for (int i = 0; i < list.Count; i++)
            {
                MessageEntity dd = list[i];
                if (dd.GetFlagNo() == me.GetFlagNo())
                {
                    //设置为已读
                    dd.isReader = true;
                    return dd;
                }
            }
            return null;
        }
    }
}
View Code

UDP发送接收监听代码 UdpSocket.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;

namespace UdpEntity
{
    public static class UdpSocket
    {
        //本机名称和IP
        public static string ComputerName;
        public static string ComputerIP;
        public const int listenProt = 12345;//设置端口号
        static UdpClient listener = null;//提供的网络服务
        static Thread listenter = null;//创建一个监听消息的进程
        static bool islistenter;//是否要监听
        static bool isconn;//是否已经在监听
        public static bool IsMsgReader;//消息是否已读

        public static void Start()
        {
            if (listenter == null || isconn)
            {
                listenter = new Thread(StartListener);
                listenter.Start();
            }
        }

        static UdpSocket()
        {
            isconn = false;
            IsMsgReader = true;
            ComputerName = Dns.GetHostName();
            ComputerIP = GetIPAddress();
            islistenter = true;
            //加下面这句是为了在开启线程中可以访问控件属性
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
            //OnListenter = Listenter;
        }
        //关闭
        public static void Close()
        {
            if (listener == null)
            {
                return;
            }
            try
            {
                isconn = false;
                listener.Close();//关闭探听消息服务
                listenter.Abort();//关闭监听消息进程
            }
            catch { }
        }
        //获取IP
        public static string GetIPAddress()
        {
            string AddressIP = "";
            //第一种办法获取
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString().ToLower() == "internetwork")
                {
                    //System.Windows.Forms.MessageBox.Show(_IPAddress.AddressFamily.ToString().ToLower()  + " - " + _IPAddress.ToString());
                    //return _IPAddress.ToString();
                }
            }
            //第二种办法获取
            if (AddressIP == "")
            {
                IPHostEntry myEntry = Dns.GetHostEntry(System.Net.Dns.GetHostName());
                if (myEntry.AddressList.Length > 1)
                {
                    if (myEntry.AddressList[0].ToString().IndexOf('.') > 0)
                    {
                        AddressIP = myEntry.AddressList[0].ToString();
                    }
                    else
                    {
                        AddressIP = myEntry.AddressList[1].ToString();
                    }
                    AddressIP = myEntry.AddressList[1].ToString();
                }
                else
                {
                    AddressIP = myEntry.AddressList[0].ToString();
                }
            }
            return AddressIP;
        }
        public delegate void Listenter(MessageEntity msg);
        public static event Listenter OnListenter;
        static List<string> lis = new List<string>();
        static MessageManage msgm = MessageManage.GetMessageManange();
        /// <summary>
        /// 截取数组
        /// </summary>
        /// <param name="src">原始数组</param>
        /// <param name="t">开始下标</param>
        /// <param name="p">截取多长</param>
        /// <returns></returns>
        private static byte[] CutByte(byte[] src, int t, int p) 
        {
            byte[] n = new byte[p];
            Buffer.BlockCopy(src, t, n, 0, n.Length);
            return n;
        }
        //开始监听
        private static void StartListener()
        {
            if (isconn == true)//已经开启监听就不要在开启了
            {
                return;
            }
            try
            {
                isconn = true;
                listener = new UdpClient(listenProt); //使用UDP协议
                IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenProt); //任意IP,
                while (islistenter)//处于监听状态
                {
                    byte[] bytes = listener.Receive(ref groupEP);
                    MessageEntity me = new MessageEntity();
                    //如果接收字节大小等于 标识字节大小
                    if (Encoding.GetEncoding("UTF-8").GetBytes(me.GetFlagNo()).Length == bytes.Length)
                    {
                        lis.Add(Encoding.GetEncoding("UTF-8").GetString(bytes, 0, bytes.Length));
                        continue;
                    }
                    me.sendIp = groupEP.Address.ToString();//发送人的IP
                    me.sendPort = groupEP.Port;//发送人的端口号

                    byte[] hd = CutByte(bytes, 0, me.getHeadToByte().Length);//头部字节
                    me = me.resetParameter(hd, me);//赋值
                    me.datas = CutByte(bytes, me.getHeadToByte().Length, bytes.Length - hd.Length);//数据字节
                    msgm.Add(me);
                    if (me.isLast == "1")
                    {
                        me = msgm.reader(me);
                        if (OnListenter != null)
                        {
                            OnListenter(me);
                        }
                    }
                }
            }
            catch {
            }
            finally
            {
                isconn = false;
                if (listener!=null)
                {
                    listener.Close();
                }
            }
        }
        static int VALUE_MAX = 2048;//接收发送最大字节 2kb
        public static void SendMessage(string ipStr, string msg)
        {
            MessageEntity me = new MessageEntity(msg);
            SendMessage(ipStr, me);
        }
        public static void SendMessage(string ipStr, MessageEntity me)
        {
            Send(ipStr, me);
        }
        /// <summary>
        /// 发送消息 string
        /// </summary>
        /// <param name="ipStr">IP</param>
        /// <param name="me">消息</param>
        private static void Send(string ipStr, MessageEntity me)
        {
            Socket s = new Socket(AddressFamily.InterNetwork,
                    SocketType.Dgram, ProtocolType.Udp);
            try
            {
                IPAddress broadcast = IPAddress.Parse(ipStr);
                IPEndPoint ep = new IPEndPoint(broadcast, listenProt);
                me.isLast = "0";//未成功
                byte[] hd = me.getHeadToByte();//未完成
                me.isLast = "1";//最后一次
                byte[] shd = me.getHeadToByte();//已完成
                if (me.isPass == "1")
                {//需要确认
                    //发送确认码
                    byte[] qrm = Encoding.GetEncoding("UTF-8").GetBytes(me.GetFlagNo());
                    s.SendTo(qrm, ep);

                    bool qm = true;
                    while (qm)
                    {
                        if (lis.Count > 0)
                        {
                            for (int i = 0; i < lis.Count; i++)
                            {
                                if (lis[i] == me.GetFlagNo())
                                {
                                    lis.RemoveAt(i);
                                    qm = false;
                                    break;
                                }
                            }
                        }
                    }
                }
                int an = hd.Length + me.datas.Length;//总长度
                if (an <= VALUE_MAX)//字节小于
                {
                    byte[] pj = msgm.CopyByte(shd, me.datas);
                    s.SendTo(pj, ep);
                }
                else//分次发送
                {
                    //byte[] hd2 = ms.getHeadToByte();//未完成的头部字节
                    int n = me.datas.Length / VALUE_MAX;
                    int d = me.datas.Length % VALUE_MAX;
                    int m = n * hd.Length;
                    int c = (m + d) / VALUE_MAX;
                    int f = (m + d) % VALUE_MAX;
                    n = n + c + (f > 0 ? 1 : 0);

                    for (int i = 0; i < n; i++)
                    {
                        if (i == (n - 1))
                        {
                            byte[] nbt = new byte[f - shd.Length];
                            nbt = CutByte(me.datas, i * (VALUE_MAX - hd.Length), nbt.Length);
                            s.SendTo(msgm.CopyByte(shd, nbt), ep);
                        }
                        else
                        {
                            byte[] nbt = new byte[VALUE_MAX - hd.Length];
                            nbt = CutByte(me.datas, i * (VALUE_MAX - hd.Length), nbt.Length);
                            s.SendTo(msgm.CopyByte(hd, nbt), ep);
                        }
                    }
                }
            }
            catch { }
            finally
            {
                s.Close();
            }
        }
    }
}
View Code

不过用处不大, 实用性很小, 感谢大家百忙之中来抽空看.^.^

原文地址:https://www.cnblogs.com/weloglog888/p/7676409.html