其实udp不存在客户端和服务端之分。我这里主要区分两个程序。因为有个程序需要指定ip.所以我就就把它叫客户端。客户端会先指定ip。并且异步方法接收消息。一旦受到消息,会交给回调函数处理。
服务端会保存客户端发来的ip和端口。用于回发。服务端也实现异步接收消息的方法。
并且消息显示方面。我用了ManualReSetevent来同步控制窗体的显示。注释写的很清楚。本人还是学生,可能注释理解有错,希望各位指点。
我觉得程序最大的特点就是界面不会卡顿,而且一旦设置好ip,客户端和服务端就能随意发送和收取消息。
我画了个图:左右两边的四个小箭头我主要想说明循环调用;
客户端代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; namespace CHEINGDDDDDDD { public partial class Form1 : Form { public Form1() { InitializeComponent(); } public static Socket udpReceive;//接收对象 public static Socket udpSend;//发送对象 public const int udpR_PROT = 9095; public const int udpS_PORT = 9096; public static byte[] udpReDataBuf;//接收字节数组 public static byte[] udpSeDataBuf;//发送字节数组 public static bool setIP = false;//用于判断ip是否正确 public static EndPoint remoteEP; public static IPEndPoint remoteIPEP; public static IPAddress remoteIpadress; public static int sendLen; public static string messageC;//收到消息的字符窜 public static string messageS;//发送消息的字符窜 public static int receiveLen;//收到消息的的长度 public static IntPtr Main_wnd_handle;//窗体句柄 public static ManualResetEvent close;//同步控制线程结束 public static ManualResetEvent come;//同步控制线程消息收 public static ManualResetEvent post;//同步控制线程消息发 public static ManualResetEvent[] list; public const int MESSAGE_SEND = 0x521;//消息常量 发送 public const int MESSAGE_CON = 0x520;//消息常量 接受 [DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage( IntPtr hWnd, int Msg, int wParam, int lParam ); public static void Setdate()//用于数据初始化 { come = new ManualResetEvent(false); close = new ManualResetEvent(false); post = new ManualResetEvent(false); list = new ManualResetEvent[3]; list[0] = close;//0 线程结束 list[1] = come;//1 消息到达 list[2] = post;//2 消息发送 //初始消息为1k udpReDataBuf = new byte[1024]; udpSeDataBuf = new byte[1024]; //初始发送的ip地址和端口的封装,会在后面的发送按钮明确ip和端口 remoteIPEP = new IPEndPoint(IPAddress.Any, 0); //用于接收的Socket的绑定,确定的端口 IPEndPoint iep = new IPEndPoint(IPAddress.Any, udpR_PROT); //new Socket收 udpReceive = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //绑定 udpReceive.Bind(iep); //注意remoteEP是EndPoint型,是抽象类,所以不能new remoteEP = (EndPoint)remoteIPEP; //BeginReceiveFrom是异步的方法接收消息,注意ref remote ,当有消息来会写入ip地址 udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object()); //new Socket 发 udpSend = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //工作线程启动 ThreadStart workStart = new ThreadStart(doing); Thread gogo = new Thread(workStart); gogo.Start(); } private void Form1_Load(object sender, EventArgs e) { //句柄赋值,初始化函数的运行和线程的启动 Main_wnd_handle = this.Handle; Setdate(); } //窗体消息回调函数。用于同步显示发送消息。 //消息来就添加到texbox2;消息发送就清空texbox3,同时显示在texbox2 protected override void DefWndProc(ref Message m) { switch (m.Msg) { case MESSAGE_CON: textBox2.AppendText("服务器:" + messageC+"\n"); break; case MESSAGE_SEND: textBox3.Clear(); textBox2.AppendText("客户机:" + messageS + "\n"); break; default: base.DefWndProc(ref m); break; } } //消息发送按钮 private void button1_Click(object sender, EventArgs e) { remoteIPEP.Address = remoteIpadress;//远程ip remoteIPEP.Port = udpS_PORT;//远程端口 messageS = textBox3.Text;//发送的消息字符串 udpSeDataBuf = Encoding.UTF8.GetBytes(messageS);//字节窜封装成字节数组 udpSend.SendTo(udpSeDataBuf, remoteIPEP);//发送 post.Set();//同步控制窗体显示 } //接收消息的回调函数 public static void ReceiveServerCallback(IAsyncResult ar) { try { //远程ip的写入,字节流转换成字符窜 EndPoint tmpremoteEP = (EndPoint)remoteIPEP; receiveLen = udpReceive.EndReceiveFrom(ar, ref tmpremoteEP); messageC = Encoding.UTF8.GetString(udpReDataBuf, 0, receiveLen); int len = receiveLen; //有消息来同步控制窗体显示 if (len != 0) { come.Set(); } //再次调用异步方法接收 udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object()); } catch (SocketException se) { MessageBox.Show(se.Message); } } //工作线程控制窗体显示 public static void doing() { int select; bool working = true; while (working) { select = WaitHandle.WaitAny(list, 1000); switch (select) { case 0: working = false; break; case 1: come.Reset(); SendMessage(Main_wnd_handle, MESSAGE_CON, 0, 0); //消息到达 break; case 2: post.Reset(); SendMessage(Main_wnd_handle, MESSAGE_SEND, 0, 0); //消息发送 break; case WaitHandle.WaitTimeout: //超时处理 break; } } } //判断写入的ip是否正确 private void button2_Click(object sender, EventArgs e) { setIP = IPAddress.TryParse(textBox1.Text, out remoteIpadress); if (!setIP) { label1.Text = "输入IP不正确"; textBox1.Focus(); } else { label1.Text = "IP地址解析正确"; } } //结束工作线程 private void button3_Click(object sender, EventArgs e) { close.Set(); } } }
服务端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Main_wnd_handle = this.Handle;
Setdate();
}
//设置变量
public const int MESSAGE_CON = 0x520;//消息常亮 收
public const int MESSAGE_SEND = 0x521;//消息常量 发
public static IntPtr Main_wnd_handle;//窗体句柄
public static Socket udpReceive;//socket 收
public static Socket udpSend;//socket 发
public const int udpR_PORT = 9096;
public const int udpS_PORT = 9095;
public static IPEndPoint remoteIPEP;
public static EndPoint remoteEP;
public static byte[] udpSeDataBuf;
public static byte[] udpReDataBuf;
public static int receiveLen;
public static string messageC;
public static string messageS;
public static ManualResetEvent post;
public static ManualResetEvent close;
public static ManualResetEvent come;
public static ManualResetEvent[] list;
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(
IntPtr hWnd,
int Msg,
int wParam,
int lParam
);
//窗体回调处理
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case MESSAGE_CON:
textBox1.AppendText("客户机:" + messageC+"\n");
break;
case MESSAGE_SEND:
textBox2.Clear();
textBox1.AppendText("服务器:" + messageS + "\n");
break;
default:
base.DefWndProc(ref m);
break;
}
}
public static void Setdate()
{
come = new ManualResetEvent(false);
post = new ManualResetEvent(false);
close = new ManualResetEvent(false);
list = new ManualResetEvent[3];
list[0] = close;
list[1] = come;
list[2] = post;
udpReDataBuf = new byte[1024];
udpSeDataBuf = new byte[1024];
remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, udpR_PORT);
udpReceive = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
udpReceive.Bind(iep);
udpSend = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
remoteEP = (EndPoint)remoteIPEP;
udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object());
ThreadStart workStart = new ThreadStart(doing);
Thread gogo = new Thread(workStart);
gogo.Start();
}
public static void doing()
{
bool linlin = true;
int select;
while (linlin)
{
select = WaitHandle.WaitAny(list, 1000);
switch (select)
{
case 0:
linlin = false;
break;
case 1:
come.Reset();
SendMessage(Main_wnd_handle, MESSAGE_CON, 0, 0);
break;
case 2:
post.Reset();
SendMessage(Main_wnd_handle, MESSAGE_SEND, 0, 0);
break;
case WaitHandle.WaitTimeout:
break;
}
}
}
public static void ReceiveServerCallback(IAsyncResult ar)
{
try
{
//实际写入远程ip的地方,所以需要个临时tmpremoteEP写入。再装换成IPEndPoint类型给remoteIPEP,用于确定会发的ip地址
EndPoint tmpremoteEP = (EndPoint)remoteIPEP;
receiveLen = udpReceive.EndReceiveFrom(ar, ref tmpremoteEP);
remoteIPEP = (IPEndPoint)tmpremoteEP;
messageC = Encoding.UTF8.GetString(udpReDataBuf, 0, receiveLen);
if (receiveLen != 0)
{
come.Set();
}
udpReceive.BeginReceiveFrom(udpReDataBuf, 0, 1024, SocketFlags.None, ref remoteEP, ReceiveServerCallback, new object());
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
private void button1_Click(object sender, EventArgs e)
{
messageS = textBox2.Text;
udpSeDataBuf = Encoding.UTF8.GetBytes(messageS);
//注意远程端口的绑定
remoteIPEP.Port = udpS_PORT;
udpSend.SendTo(udpSeDataBuf, remoteIPEP);
post.Set();
}
}
}

我画了个图:左右两边的四个小箭头我主要想说明循环调用;
原文:http://www.cnblogs.com/my-project1/p/4606203.html