UDP Server 程式碼(二)
PS:
在Win7 64Bit 下執行發生問題
IPEndPoint mIPPoint = new IPEndPoint(IPAddress.Any, mPort);
mSocketServer.Bind(mIPPoint); <== 問題發生點,還未解決
訊息: {"一次只能用一個通訊端位址 (通訊協定/網路位址/連接埠)。"}
問題已經找到解決方法但原因未明確 : @@ Port 被佔用了@@
我將 UdpServer 在FormLoad 中實體化,並執行Socket.Bind(IPEndPoint) 造成錯誤。{"一次只能用一個通訊端位址 (通訊協定/網路位址/連接埠)。"}
只要在 FormLoad 完成後,以Timer 或 Button.Clock 執行就不會發生。
另,在MS Vistudio 2010 的 Debug環境中,發現 xxxxx.vshost.exe 總是在背景中被執行著,該項尚未澄清是否會影響 Socket.Bind(IPEndPoint) 。
因為,當發生{"一次只能用一個通訊端位址 (通訊協定/網路位址/連接埠)。"} 後,我用手動更改 Port 後就可正常運作。我懷疑是 Debug環境造成。
該版本,修正同一個 IP 要求不同 Port 的問題,同一個事件處裡程式可以處裡多個 Port 的服務。
主要將 UdpEventArgs 的建構式參數原用
UdpEventArgs (Stream msg, string ip)
改成
UdpEventArgs(Stream msg, IPEndPoint ipend)
UDP Server 程式碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace SBM75e_4
{
/// <summary>
/// 事件委派宣告
/// </summary>
public delegate void UdpEventHandler(object sender, UdpEventArgs e);
public class UDP_Server
{
/// <summary>
/// 非同步接收資料的回呼
/// </summary>
private void EndRecvCallBack(IAsyncResult result)
{
try
{
/*傳回非同步物件*/
Socket mResultSocket = result.AsyncState as Socket;
/*呼叫 EndReceiveFrom 非同步接收*/
int mRecvBytes = mResultSocket.EndReceiveFrom(result, ref mRemotePoint);
/*將資料置入Stream */
Stream mStream = BytesToStream(mRecvBuffer, mRecvBytes);
/* Invoke */
((System.Windows.Forms.Form)mOwner).Invoke(
mSetUdpReceivedDlg,
mStream,
(IPEndPoint)mRemotePoint
); //.. List<byte>
}
catch (Exception ex)
{
//((System.Windows.Forms.Form)m_Owner).Invoke(m_SetUdpReceivedDlg, ex.Message); //??????
}
finally
{
/*重新呼叫非同步接收*/
mSocketServer.BeginReceiveFrom(
mRecvBuffer,
0,
mRecvBuffer.Length,
SocketFlags.None,
ref mRemotePoint,
new AsyncCallback(EndRecvCallBack),
mSocketServer
);
}
}
#region 公用程式 Bytes、Stream 轉換
/// <summary>
/// 將 Byte陣列 轉為 Stream
/// </summary>
/// <returns>Stream</returns>
public static Stream BytesToStream(byte[] bytes)
{
Stream stream = new MemoryStream(bytes);
return stream;
}
public static Stream BytesToStream(byte[] bytes, int Length)
{
Stream stream = new MemoryStream(bytes, 0, Length);
return stream;
}
/// <summary>
/// 將 Stream 轉為 Byte陣列
/// </summary>
public static byte[] StreamToBytes(Stream stream)
{
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
/*將 stream 指針指向開頭*/
stream.Seek(0, SeekOrigin.Begin);
return bytes;
}
#endregion
/// <summary>
/// 委派處理函式
/// </summary>
//private void OnUdpReceivedText(Stream msg, string ip, int port)
private void OnUdpReceivedText(Stream msg, IPEndPoint ipend)
{
UdpEventArgs e = new UdpEventArgs(msg, ipend);
if (UdpReceived != null) //. 當事件變數不為 null 則執行之
{
UdpReceived(this, e);
}
}
/// <summary>
/// 委派宣告
/// </summary>
private delegate void SetUdpReceived(Stream msg, IPEndPoint ipend);
/// <summary>
/// 委派欄位
/// </summary>
private SetUdpReceived mSetUdpReceivedDlg;
/// <summary>
/// 本機端 Socket物件
/// </summary>
private Socket mSocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
/// <summary>
/// 接收資料的緩衝區
/// </summary>
private byte[] mRecvBuffer=new byte[10240];
/// <summary>
/// 初始化遠端IP和 Port端點物件
/// </summary>
private EndPoint mRemotePoint = new IPEndPoint(IPAddress.Any, 0);
/// <summary>
/// 服務 Port
/// </summary>
private int mPort = 0;
/// <summary>
/// 儲存擁有者
/// </summary>
private object mOwner;
/// <summary>
/// UDP Received 事件
/// </summary>
public event UdpEventHandler UdpReceived;
/// <summary>
/// 建構式
/// </summary>
public UDP_Server(object Owner, int APort)
{
mOwner = Owner;
mPort = APort;
/*初始化Sockt物件*/
mSocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
/*指定要以機器上所有的網路介面,開啟的 Port*/
IPEndPoint mIPPoint = new IPEndPoint(IPAddress.Any, mPort);
/*繫結 IP 和 Port 資訊*/
mSocketServer.Bind(mIPPoint);
/*設定委派處理函式*/
mSetUdpReceivedDlg = OnUdpReceivedText;
//..啟動非同步接受資料
mSocketServer.BeginReceiveFrom(
mRecvBuffer,
0,
mRecvBuffer.Length,
SocketFlags.None,
ref mRemotePoint,
new AsyncCallback(EndRecvCallBack),
mSocketServer
);
}
/*建立以 UCP 為協定的Socket*/
Socket m_SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress m_RemoteAddress = new IPAddress(0);
public int UDP_Send(String RemoteIP, int RemotePort, byte[] TxBuffer, int ByteCount)
{
//("遠端IP位置 : ");
// IPAddress m_RemoteAddress = IPAddress.Parse(RemoteIP) ;
// if (m_RemoteAddress != null)
if (IPAddress.TryParse(RemoteIP, out m_RemoteAddress))
{
/*初始化IPEndPoint物件,表示要連結的遠端IP位置和Port號*/
EndPoint m_IPPoint = new IPEndPoint(m_RemoteAddress, RemotePort);
try
{
/*送出訊息*/
m_SocketClient.SendTo(TxBuffer, m_IPPoint);
return (0);
}
catch
{
return (-1);
}
}
return (-1);
}
}
/// <summary>
/// 定義專用事件參數類別
/// </summary>
public class UdpEventArgs:EventArgs
{
private IPEndPoint mIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
private Stream mMSG = new MemoryStream();
public UdpEventArgs(Stream msg, IPEndPoint ipend)
{
MSG = msg;
mIpEndPoint.Address = ipend.Address;
mIpEndPoint.Port = ipend.Port;
}
public IPEndPoint EndPoint
{
get { return mIpEndPoint; }
private set { mIpEndPoint = value; }
}
public Stream MSG
{
get { return mMSG; }
private set { mMSG = value; }
}
}
}
使用該 Classint iPort = 5168;
UDP_Server udpADAM;
啟動UDP封包接收伺服
udpADAM = new UDP_Server(this, iPort); // 建立物件
udpADAM.UdpReceived += onUdpReceived; // 串接事件
事件程式可以處裡多個 Port 的服務
/* UDP Server 事件 */
private void onUdpReceived(object sender, UdpEventArgs e)
{
Byte[] bytes = UDP_Server.StreamToBytes(e.MSG);
// e.EndPoint.Address;
switch (e.EndPoint.Port)
{
case 4001:
break;
case 4002:
break;
case 4003:
break;
case 4004:
break;
default:
break;
}
// .....
}
沒有留言:
張貼留言