UDP通信简单 小结
Android手机版和电脑版 效果图: 通过WiFi局域网 电脑和手机连接通信. 电脑版本和手机版本使用了相同的消息发送头协议, 可以相互接收消息. 若有做的不好的地方还希望大家指导一下.
1. 手机版
添加权限 AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
页面 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>
后台代码 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");
}
};
};
}
以下是类库代码:
获取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; } } }
发送接收消息包装类库 :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; } }
管理消息类(主要是针对发送消息过大,分批发送使用) : 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; } }
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; } }
以上是所有代码, 最简单的调用如下 实现发送接收
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());
2. 电脑版本 c#
当类库写完之后最简单的调用如下:
//放在窗体初始化上面 UdpSocket.OnListenter += recive; InitializeComponent();//初始控件 //加载事件 UdpSocket.Start();//开启监听[线程] //窗体关闭事件 UdpSocket.Close();//关闭监听[线程] //发送消息 UdpSocket.SendMessage("目标IP地址", "消息"); //定义接收消息的方法 private void recive(MessageEntity msg) { //消息封装在了MessageEntity中 //通过 msg.GetString() 获取消息 }
以下是全部代码:
窗体初始化控件代码自动生成的
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; } }
窗体后台代码
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 = ""; } } } }
封装的接收消息类库 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 } }
消息管理类库 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; } } }
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(); } } } }
不过用处不大, 实用性很小, 感谢大家百忙之中来抽空看.^.^