socket通訊問題
阿新 • • 發佈:2018-11-04
2015年12月11日 14:55:04 yiqijinbu 閱讀數:3035
TCP:面向連線的,所以在服務端繫結埠後,需要監聽Listen()是否有客戶端傳送請求,有的話,Accept()建立一個新的socket物件,用於傳送和接收資訊,
就想先建造了一條高速路,再建造一輛貨車拉貨。
UDP:無連線的,所以在服務端繫結埠後,不需要監聽Listen(),也不用建立一個新的socket物件用於接收發送資訊,但是在傳送和接收時,要講本身的埠
做引數傳送給對方,這樣在交流時,對方才能確定自己。
UDP協議:
Client端:
static void Main(string[] args) { int port = 2001; string strHost = GetAddressIP();// "127.0.0.1"; // 建立IP物件 IPAddress ip = IPAddress.Parse(strHost); // 建立埠物件 IPEndPoint ipe = new IPEndPoint(ip, port); // 建立socket物件 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); Console.WriteLine("連線中。。。"); // 向伺服器傳送訊息 string strMsgToServe = "嗨,來自客戶端的問候。。。"; // 轉成二進位制傳送到服務端 byte[] bytMsgToServe = Encoding.UTF8.GetBytes(strMsgToServe); socket.SendTo(bytMsgToServe, bytMsgToServe.Length, SocketFlags.None, ipe); Console.WriteLine("訊息已傳送。。。"); //IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint Remote = new IPEndPoint(IPAddress.Any, 0);//(EndPoint)sender; bytMsgToServe = new byte[1024]; int recv = socket.ReceiveFrom(bytMsgToServe, ref Remote);//接受來自伺服器的資料 Console.WriteLine("Message received from{0}:", Remote.ToString()); Console.WriteLine("收到的服務端訊息:"+Encoding.UTF8.GetString(bytMsgToServe, 0, recv)); socket.Close(); Console.ReadLine(); } /// <summary> /// 獲取本地IP地址資訊 /// </summary> public static string GetAddressIP() { ///獲取本地的IP地址 string AddressIP = string.Empty; foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList) { if (_IPAddress.AddressFamily.ToString() == "InterNetwork") { AddressIP = _IPAddress.ToString(); } } return AddressIP; }
Server端:
static void Main(string[] args) { int port = 2001; string strHost = GetAddressIP();// "127.0.0.1"; // 建立終結點 IPAddress ip = IPAddress.Parse(strHost); // 建立網路埠 IPEndPoint ipe = new IPEndPoint(ip, port); // 建立socke,開始監聽--SocketType列舉 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // 繫結埠 socket.Bind(ipe); Console.WriteLine("等待客戶端連線。。。"); //IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);//定義要傳送的計算機的地址 EndPoint Remote = new IPEndPoint(IPAddress.Any, 0);//(EndPoint)(sender); // 收到的二進位制byte byte[] bytRecv = new byte[1024]; int intBytes = socket.ReceiveFrom(bytRecv, ref Remote);//接受來自伺服器的資料 //Console.WriteLine("Message received from{0}:", Remote.ToString()); Console.WriteLine("收到的資訊:-"+Encoding.UTF8.GetString(bytRecv, 0, intBytes)); string welcome = "Welcome to my test server!"; bytRecv = Encoding.ASCII.GetBytes(welcome); socket.SendTo(bytRecv, bytRecv.Length, SocketFlags.None, Remote); Console.ReadLine(); } /// <summary> /// 獲取本地IP地址資訊 /// </summary> public static string GetAddressIP() { ///獲取本地的IP地址 string AddressIP = string.Empty; foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList) { if (_IPAddress.AddressFamily.ToString() == "InterNetwork") { AddressIP = _IPAddress.ToString(); } } return AddressIP; }
當將服務層寫成window服務時,如果客戶端關閉,服務端會報錯,“遠端主機關閉了一個現有的連結”,然後整個服務都停止了。
解決辦法:為socket物件設定低階操作模式
// 為 Socket 設定低階操作模式,不然當客戶端關閉的時候,會報錯
uint IOC_IN = 0x80000000;
uint IOC_VENDOR = 0x18000000;
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
另外,在window服務中,定時控制元件是不能用的,但是也不報錯,不提醒,如果要定時迴圈,
解決辦法:
System.Timers.Timer tmrSelectCOM = new System.Timers.Timer(2000);
tmrSelectCOM.Elapsed += new System.Timers.ElapsedEventHandler(tmrSelectCOM_Tick);
tmrSelectCOM.Enabled = true;
TCP協議:
服務端:
static void Main(string[] args)
{
// ip地址,埠
int port = 2000;
string strIp = GetAddressIP();
// IP物件
IPAddress ip = IPAddress.Parse(strIp);
IPEndPoint ipe = new IPEndPoint(ip, port);
// 例項化socket物件
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 繫結埠
socket.Bind(ipe);
// 監聽
socket.Listen(0);
// 為傳送請求的客戶端建立新的socket物件
Socket temp = socket.Accept();
// 接收訊息
byte[] bytRecv = new byte[1024];
int intCount = temp.Receive(bytRecv,bytRecv.Length,0);
string strRecv = Encoding.UTF8.GetString(bytRecv, 0, intCount);
Console.WriteLine(strRecv);
// 傳送訊息
string strSendMsg = "來自服務端的問候。。。";
byte[] bytSendMsg = Encoding.UTF8.GetBytes(strSendMsg);
temp.Send(bytSendMsg, 0, bytSendMsg.Length, 0);
Console.WriteLine("服務端訊息已傳送。。。");
Console.ReadLine();
}
private static string GetAddressIP()
{
string strAddressIP = string.Empty;
foreach (IPAddress address in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
{
if (address.AddressFamily.ToString() == "InterNetwork")
{
strAddressIP = address.ToString();
}
}
return strAddressIP;
}
- 客戶端:
public static void Main(string[] args)
{
int port = 2000;
string strIp = GetAddressIP();
// IP物件
IPAddress ip = IPAddress.Parse(strIp);
IPEndPoint ipe = new IPEndPoint(ip, port);
// 建立socket物件
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 連線
socket.Connect(ipe);
Console.WriteLine("已連線。。。");
// 傳送資訊
string strSendMsg="來自客戶端的問候。。。";
byte[] bytSendMsg = Encoding.UTF8.GetBytes(strSendMsg);
socket.Send(bytSendMsg, 0, bytSendMsg.Length, SocketFlags.None);
Console.WriteLine("訊息已傳送。。。");
// 接收
byte[] bytRecvMsg = new byte[1024];
int intCount = socket.Receive(bytRecvMsg);
string strRecvMsg = Encoding.UTF8.GetString(bytRecvMsg, 0, intCount);
Console.WriteLine(strRecvMsg);
Console.ReadLine();
}
private static string GetAddressIP()
{
// 獲取本地的IP地址
string AddressIP = string.Empty;
foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
{
if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
{
AddressIP = _IPAddress.ToString();
}
}
return AddressIP;
}
TCP圖:
UDP圖: