UDP通訊簡單 小結

Android手機版和電腦版 效果圖: 經過WiFi局域網 電腦和手機鏈接通訊. 電腦版本和手機版本使用了相同的消息發送頭協議, 能夠相互接收消息. 如有作的很差的地方還但願你們指導一下.java

 

1. 手機版android

添加權限 AndroidManifest.xmlc#

    <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() + "\n");
                            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() + "\n");

            }
        };
    };

}
View Code

如下是類庫代碼:網絡

獲取IP地址 IPUtils.java 可要可不要app

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.javadom

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.javasocket

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("\r\n消息來自: [ " + msg.sendIp + " ]\r\n" + 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

不過用處不大, 實用性很小, 感謝你們百忙之中來抽空看.^.^

相關文章
相關標籤/搜索