如何解决C#异步套接字编程Client/Server问题?
How to solve C# Asynchronous Socket Programming Client/Server problem?
我找到了一篇关于此程序的文章。
(https://www.gokhan-gokalp.com/en/c-ile-asenkron-socket-programlama/)
但我有问题,它没有将信息服务器发送到客户端。
我必须在客户端编写接收方法,我必须在服务器端正确发送方法。他们失踪了。
我该如何实施?
客户端:主程序
using ExampleClient.Sockets;
using ExampleDataTransferObjects;
using System;
using System.Net;
using System.Linq;
namespace ExampleClient
{
class Program
{
static void Main(string[] args)
{
int port = 5555;
Console.WriteLine(string.Format("Client Başlatıldı. Port: {0}", port));
Console.WriteLine("-----------------------------");
ExampleSocket exampleSocket = new ExampleSocket(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
exampleSocket.Start();
Console.WriteLine("Göndermek için \"G\", basınız...");
int count = 1;
while (Console.ReadLine().ToUpper() == "G")
{
ExampleDTO exampleDTO = new ExampleDTO()
{
Status = string.Format("{0}. Alındı", count),
Message = string.Format("{0} ip numaralı client üzerinden geliyorum!", GetLocalIPAddress())
};
exampleSocket.SendData(exampleDTO);
count++;
}
Console.ReadLine();
}
static string GetLocalIPAddress()
{
string localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault().ToString();
return localIP;
}
}
}
Client.cs: 此客户端将向服务器传递数据。
using ExampleDataTransferObjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
namespace ExampleClient.Sockets
{
public class ExampleSocket
{
#region Variables
Socket _Socket;
IPEndPoint _IPEndPoint;
// Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
SocketError socketError;
byte[] tempBuffer = new byte[1024];
#endregion
#region Constructor
public ExampleSocket(IPEndPoint ipEndPoint)
{
_IPEndPoint = ipEndPoint;
// Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz.
// TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
#endregion
#region Public Methods
public void Start()
{
// BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
_Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
}
public void SendData(ExampleDTO exampleDTO)
{
using (var ms = new MemoryStream())
{
// İlgili object'imizi binary'e serialize ediyoruz.
new BinaryFormatter().Serialize(ms, exampleDTO);
IList<ArraySegment<byte>> data = new List<ArraySegment<byte>>();
data.Add(new ArraySegment<byte>(ms.ToArray()));
// Gönderme işlemine başlıyoruz.
_Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
{
// Gönderme işlemini bitiriyoruz.
int length = _Socket.EndSend(asyncResult, out socketError);
if (length <= 0 || socketError != SocketError.Success)
{
Console.WriteLine("Server bağlantısı koptu!");
return;
}
}, null);
if (socketError != SocketError.Success)
Console.WriteLine("Server bağlantısı koptu!");
}
}
#endregion
#region Private Methods
void OnBeginConnect(IAsyncResult asyncResult)
{
try
{
// Bağlanma işlemini bitiriyoruz.
_Socket.EndConnect(asyncResult);
// Bağlandığımız socket üzerinden datayı dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
}
catch (SocketException)
{
// Servera bağlanamama durumlarında bize SocketException fırlatıcaktır. Hataları burada handle edebilirsiniz.
Console.WriteLine("Servera bağlanılamıyor!");
}
}
void OnBeginReceive(IAsyncResult asyncResult)
{
// Almayı bitiriyoruz ve geriye gelen byte array'in boyutunu vermektedir.
int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);
if (receivedDataLength <= 0 || socketError != SocketError.Success)
{
// Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
Console.WriteLine("Server bağlantısı koptu!");
return;
}
// Tekrardan socket üzerinden datayı dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
}
#endregion
}
}
ExampleDataTransferObjects.dll: 这个dll将数据客户端传输到服务器
using System;
namespace ExampleDataTransferObjects
{
/// <summary>
/// Serialize edebilmek için Serializable attributü ile işaretliyoruz.
/// </summary>
[Serializable]
public class ExampleDTO
{
public string Status { get; set; }
public string Message { get; set; }
}
}
服务器端:
Client.cs: 它将接收数据并发送给监听器
using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
namespace ExampleServer.Sockets
{
public delegate void OnExampleDTOReceived(ExampleDTO eDTO);
public class Client
{
#region Variables
public OnExampleDTOReceived _OnExampleDTOReceived;
Socket _Socket;
// Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
SocketError socketError;
byte[] tempBuffer = new byte[1024]; // 1024 boyutunda temp bir buffer, gelen verinin boyutu kadarıyla bunu receive kısmında handle edeceğiz.
#endregion
#region Constructor
public Client(Socket socket)
{
_Socket = socket;
}
#endregion
#region Public Methods
public void Start()
{
// Socket üzerinden data dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
}
#endregion
#region Private Methods
void OnBeginReceiveCallback(IAsyncResult asyncResult)
{
// Almayı bitiriyoruz ve gelen byte array'in boyutunu vermektedir.
int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);
if (receivedDataLength <= 0 && socketError != SocketError.Success)
{
// Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
return;
}
// Gelen byte array boyutunda yeni bir byte array oluşturuyoruz.
byte[] resizedBuffer = new byte[receivedDataLength];
Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);
// Gelen datayı burada ele alacağız.
HandleReceivedData(resizedBuffer);
// Tekrardan socket üzerinden data dinlemeye başlıyoruz.
// Start();
// Socket üzerinden data dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
}
/// <summary>
/// Gelen datayı handle edeceğimiz nokta.
/// </summary>
/// <param name="resizedBuffer"></param>
void HandleReceivedData(byte[] resizedBuffer)
{
if (_OnExampleDTOReceived != null)
{
using (var ms = new MemoryStream(resizedBuffer))
{
// BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate'e parametre olarak geçiyoruz.
ExampleDTO exampleDTO = new BinaryFormatter().Deserialize(ms) as ExampleDTO;
_OnExampleDTOReceived(exampleDTO);
}
}
}
#endregion
}
}
监听器:异步监听数据
using ExampleDataTransferObjects;
using System;
using System.Net;
using System.Net.Sockets;
namespace ExampleServer.Sockets
{
public class Listener
{
#region Variables
Socket _Socket;
int _Port;
int _MaxConnectionQueue;
#endregion
#region Constructor
public Listener(int port, int maxConnectionQueue)
{
_Port = port;
_MaxConnectionQueue = maxConnectionQueue;
// Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz.
// TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
#endregion
#region Public Methods
public void Start()
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, _Port);
// Socket'e herhangi bir yerden ve belirttiğimiz porttan gelecek olan bağlantıları belirtmeliyiz.
_Socket.Bind(ipEndPoint);
// Socketten gelecek olan bağlantıları dinlemeye başlıyoruz ve maksimum dinleyeceği bağlantıyı belirtiyoruz.
_Socket.Listen(_MaxConnectionQueue);
// BeginAccept ile asenkron olarak gelen bağlantıları kabul ediyoruz.
_Socket.BeginAccept(OnBeginAccept, _Socket);
}
#endregion
#region Private Methods
void OnBeginAccept(IAsyncResult asyncResult)
{
Socket socket = _Socket.EndAccept(asyncResult);
Client client = new Client(socket);
// Client tarafından gönderilen datamızı işleyeceğimiz kısım.
client._OnExampleDTOReceived += new Sockets.OnExampleDTOReceived(OnExampleDTOReceived);
client.Start();
// Tekrardan dinlemeye devam diyoruz.
_Socket.BeginAccept(OnBeginAccept, null);
}
void OnExampleDTOReceived(ExampleDTO exampleDTO)
{
// Client tarafından gelen data, istediğiniz gibi burada handle edebilirsiniz senaryonuza göre.
Console.WriteLine(string.Format("Status: {0}", exampleDTO.Status));
Console.WriteLine(string.Format("Message: {0}", exampleDTO.Message));
}
#endregion
}
}
服务器主程序:
using ExampleServer.Sockets;
using System;
namespace ExampleServer
{
class Program
{
static void Main(string[] args)
{
int port = 5555;
Console.WriteLine(string.Format("Server Başlatıldı. Port: {0}", port));
Console.WriteLine("-----------------------------");
Listener listener = new Listener(port, 50);
listener.Start();
Console.ReadLine();
}
}
}
我建议您使用 signalR 在客户端和服务器之间进行全双工通信。
https://docs.microsoft.com/tr-tr/aspnet/signalr/overview/getting-started/introduction-to-signalr
另外,我修改了你的ServerToClient通信代码,你可以在下面找到。
在ExampleSocket.cs中定义两个新变量
#region Variables
Socket _Socket;
IPEndPoint _IPEndPoint;
//new
SocketError socketError;
byte[] tempBuffer = new byte[1024];
//new
#endregion
在 ExampleSocket.cs 中,将下面一行添加到您的 Start() 函数中
public void Start()
{
// BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
_Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
//new
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
//new
}
在ExampleSocket.cs中添加如下新函数
//new
void OnBeginReceiveCallback(IAsyncResult asyncResult)
{
int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);
if (receivedDataLength <= 0 && socketError != SocketError.Success)
return;
byte[] resizedBuffer = new byte[receivedDataLength];
Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);
using (var ms = new MemoryStream(resizedBuffer))
{
ms.Position = 0;
string myStr = new StreamReader(ms).ReadToEnd();
Console.WriteLine(string.Format("From server : {0}", myStr));
}
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
}
//new
在Listener.cs中添加如下新函数
//new
public void Send(string s)
{
client.Send(s);
}
//new
在Client.cs中添加如下新函数
//new
public void Send(string s)
{
if (_Socket.Connected)
{
Byte[] byteData = Encoding.ASCII.GetBytes(s.ToCharArray());
_Socket.Send(byteData, byteData.Length, 0);
}
}
//new
在 ExampleServer.Program 中,修改您的 Main(string[] args) 函数
static void Main(string[] args)
{
int port = 5555;
Console.WriteLine(string.Format("Server Başlatıldı. Port: {0}", port));
Console.WriteLine("-----------------------------");
Listener listener = new Listener(port, 50);
listener.Start();
//new
bool dewamke = true;
while (dewamke)
{
Console.WriteLine("Write exit to close or write anything for sending data.");
var cmd = Console.ReadLine();
if (cmd == "exit")
dewamke = false;
else
listener.Send(cmd);
}
Console.WriteLine("closing server.");
Console.ReadLine();
//new
}
我用这段代码解决了 client.cs 中的问题:
void HandleReceivedData(byte[] resizedBuffer)
{
if (_OnExampleDTOReceived != null)
{
//using (var ms = new MemoryStream(resizedBuffer))
//{
// // BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate'e parametre olarak geçiyoruz.
// string exampleDTO = new BinaryFormatter().Deserialize(ms) as string;
// if (exampleDTO == "POSALIVE")
// SendData("ACK");
// _OnExampleDTOReceived(exampleDTO);
//}
using (MemoryStream stream = new MemoryStream(resizedBuffer))
{
stream.Position = 0;
var sr = new StreamReader(stream);
string myStr = sr.ReadToEnd();
if (myStr.Contains("POSALIVE"))
SendData("ACK");
_OnExampleDTOReceived(myStr);
}
}
}
public void SendData(string message)
{
using (var ms = new MemoryStream())
{
// İlgili object'imizi binary'e serialize ediyoruz.
new BinaryFormatter().Serialize(ms, message);
IList<ArraySegment<byte>> data = new List<ArraySegment<byte>>();
data.Add(new ArraySegment<byte>(ms.ToArray()));
// Gönderme işlemine başlıyoruz.
_Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
{
// Gönderme işlemini bitiriyoruz.
int length = _Socket.EndSend(asyncResult, out socketError);
if (length <= 0 || socketError != SocketError.Success)
{
log.append("Server bağlantısı koptu!", "");
return;
}
}, null);
if (socketError != SocketError.Success)
log.append("Server bağlantısı koptu!", "");
}
}
我在client.cs
中添加了发送数据方法
我找到了一篇关于此程序的文章。 (https://www.gokhan-gokalp.com/en/c-ile-asenkron-socket-programlama/)
但我有问题,它没有将信息服务器发送到客户端。 我必须在客户端编写接收方法,我必须在服务器端正确发送方法。他们失踪了。 我该如何实施?
客户端:主程序
using ExampleClient.Sockets;
using ExampleDataTransferObjects;
using System;
using System.Net;
using System.Linq;
namespace ExampleClient
{
class Program
{
static void Main(string[] args)
{
int port = 5555;
Console.WriteLine(string.Format("Client Başlatıldı. Port: {0}", port));
Console.WriteLine("-----------------------------");
ExampleSocket exampleSocket = new ExampleSocket(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
exampleSocket.Start();
Console.WriteLine("Göndermek için \"G\", basınız...");
int count = 1;
while (Console.ReadLine().ToUpper() == "G")
{
ExampleDTO exampleDTO = new ExampleDTO()
{
Status = string.Format("{0}. Alındı", count),
Message = string.Format("{0} ip numaralı client üzerinden geliyorum!", GetLocalIPAddress())
};
exampleSocket.SendData(exampleDTO);
count++;
}
Console.ReadLine();
}
static string GetLocalIPAddress()
{
string localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault().ToString();
return localIP;
}
}
}
Client.cs: 此客户端将向服务器传递数据。
using ExampleDataTransferObjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
namespace ExampleClient.Sockets
{
public class ExampleSocket
{
#region Variables
Socket _Socket;
IPEndPoint _IPEndPoint;
// Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
SocketError socketError;
byte[] tempBuffer = new byte[1024];
#endregion
#region Constructor
public ExampleSocket(IPEndPoint ipEndPoint)
{
_IPEndPoint = ipEndPoint;
// Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz.
// TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
#endregion
#region Public Methods
public void Start()
{
// BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
_Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
}
public void SendData(ExampleDTO exampleDTO)
{
using (var ms = new MemoryStream())
{
// İlgili object'imizi binary'e serialize ediyoruz.
new BinaryFormatter().Serialize(ms, exampleDTO);
IList<ArraySegment<byte>> data = new List<ArraySegment<byte>>();
data.Add(new ArraySegment<byte>(ms.ToArray()));
// Gönderme işlemine başlıyoruz.
_Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
{
// Gönderme işlemini bitiriyoruz.
int length = _Socket.EndSend(asyncResult, out socketError);
if (length <= 0 || socketError != SocketError.Success)
{
Console.WriteLine("Server bağlantısı koptu!");
return;
}
}, null);
if (socketError != SocketError.Success)
Console.WriteLine("Server bağlantısı koptu!");
}
}
#endregion
#region Private Methods
void OnBeginConnect(IAsyncResult asyncResult)
{
try
{
// Bağlanma işlemini bitiriyoruz.
_Socket.EndConnect(asyncResult);
// Bağlandığımız socket üzerinden datayı dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
}
catch (SocketException)
{
// Servera bağlanamama durumlarında bize SocketException fırlatıcaktır. Hataları burada handle edebilirsiniz.
Console.WriteLine("Servera bağlanılamıyor!");
}
}
void OnBeginReceive(IAsyncResult asyncResult)
{
// Almayı bitiriyoruz ve geriye gelen byte array'in boyutunu vermektedir.
int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);
if (receivedDataLength <= 0 || socketError != SocketError.Success)
{
// Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
Console.WriteLine("Server bağlantısı koptu!");
return;
}
// Tekrardan socket üzerinden datayı dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
}
#endregion
}
}
ExampleDataTransferObjects.dll: 这个dll将数据客户端传输到服务器
using System;
namespace ExampleDataTransferObjects
{
/// <summary>
/// Serialize edebilmek için Serializable attributü ile işaretliyoruz.
/// </summary>
[Serializable]
public class ExampleDTO
{
public string Status { get; set; }
public string Message { get; set; }
}
}
服务器端:
Client.cs: 它将接收数据并发送给监听器
using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
namespace ExampleServer.Sockets
{
public delegate void OnExampleDTOReceived(ExampleDTO eDTO);
public class Client
{
#region Variables
public OnExampleDTOReceived _OnExampleDTOReceived;
Socket _Socket;
// Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
SocketError socketError;
byte[] tempBuffer = new byte[1024]; // 1024 boyutunda temp bir buffer, gelen verinin boyutu kadarıyla bunu receive kısmında handle edeceğiz.
#endregion
#region Constructor
public Client(Socket socket)
{
_Socket = socket;
}
#endregion
#region Public Methods
public void Start()
{
// Socket üzerinden data dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
}
#endregion
#region Private Methods
void OnBeginReceiveCallback(IAsyncResult asyncResult)
{
// Almayı bitiriyoruz ve gelen byte array'in boyutunu vermektedir.
int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);
if (receivedDataLength <= 0 && socketError != SocketError.Success)
{
// Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
return;
}
// Gelen byte array boyutunda yeni bir byte array oluşturuyoruz.
byte[] resizedBuffer = new byte[receivedDataLength];
Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);
// Gelen datayı burada ele alacağız.
HandleReceivedData(resizedBuffer);
// Tekrardan socket üzerinden data dinlemeye başlıyoruz.
// Start();
// Socket üzerinden data dinlemeye başlıyoruz.
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
}
/// <summary>
/// Gelen datayı handle edeceğimiz nokta.
/// </summary>
/// <param name="resizedBuffer"></param>
void HandleReceivedData(byte[] resizedBuffer)
{
if (_OnExampleDTOReceived != null)
{
using (var ms = new MemoryStream(resizedBuffer))
{
// BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate'e parametre olarak geçiyoruz.
ExampleDTO exampleDTO = new BinaryFormatter().Deserialize(ms) as ExampleDTO;
_OnExampleDTOReceived(exampleDTO);
}
}
}
#endregion
}
}
监听器:异步监听数据
using ExampleDataTransferObjects;
using System;
using System.Net;
using System.Net.Sockets;
namespace ExampleServer.Sockets
{
public class Listener
{
#region Variables
Socket _Socket;
int _Port;
int _MaxConnectionQueue;
#endregion
#region Constructor
public Listener(int port, int maxConnectionQueue)
{
_Port = port;
_MaxConnectionQueue = maxConnectionQueue;
// Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz.
// TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
#endregion
#region Public Methods
public void Start()
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, _Port);
// Socket'e herhangi bir yerden ve belirttiğimiz porttan gelecek olan bağlantıları belirtmeliyiz.
_Socket.Bind(ipEndPoint);
// Socketten gelecek olan bağlantıları dinlemeye başlıyoruz ve maksimum dinleyeceği bağlantıyı belirtiyoruz.
_Socket.Listen(_MaxConnectionQueue);
// BeginAccept ile asenkron olarak gelen bağlantıları kabul ediyoruz.
_Socket.BeginAccept(OnBeginAccept, _Socket);
}
#endregion
#region Private Methods
void OnBeginAccept(IAsyncResult asyncResult)
{
Socket socket = _Socket.EndAccept(asyncResult);
Client client = new Client(socket);
// Client tarafından gönderilen datamızı işleyeceğimiz kısım.
client._OnExampleDTOReceived += new Sockets.OnExampleDTOReceived(OnExampleDTOReceived);
client.Start();
// Tekrardan dinlemeye devam diyoruz.
_Socket.BeginAccept(OnBeginAccept, null);
}
void OnExampleDTOReceived(ExampleDTO exampleDTO)
{
// Client tarafından gelen data, istediğiniz gibi burada handle edebilirsiniz senaryonuza göre.
Console.WriteLine(string.Format("Status: {0}", exampleDTO.Status));
Console.WriteLine(string.Format("Message: {0}", exampleDTO.Message));
}
#endregion
}
}
服务器主程序:
using ExampleServer.Sockets;
using System;
namespace ExampleServer
{
class Program
{
static void Main(string[] args)
{
int port = 5555;
Console.WriteLine(string.Format("Server Başlatıldı. Port: {0}", port));
Console.WriteLine("-----------------------------");
Listener listener = new Listener(port, 50);
listener.Start();
Console.ReadLine();
}
}
}
我建议您使用 signalR 在客户端和服务器之间进行全双工通信。 https://docs.microsoft.com/tr-tr/aspnet/signalr/overview/getting-started/introduction-to-signalr
另外,我修改了你的ServerToClient通信代码,你可以在下面找到。
在ExampleSocket.cs中定义两个新变量
#region Variables
Socket _Socket;
IPEndPoint _IPEndPoint;
//new
SocketError socketError;
byte[] tempBuffer = new byte[1024];
//new
#endregion
在 ExampleSocket.cs 中,将下面一行添加到您的 Start() 函数中
public void Start()
{
// BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
_Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
//new
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
//new
}
在ExampleSocket.cs中添加如下新函数
//new
void OnBeginReceiveCallback(IAsyncResult asyncResult)
{
int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);
if (receivedDataLength <= 0 && socketError != SocketError.Success)
return;
byte[] resizedBuffer = new byte[receivedDataLength];
Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);
using (var ms = new MemoryStream(resizedBuffer))
{
ms.Position = 0;
string myStr = new StreamReader(ms).ReadToEnd();
Console.WriteLine(string.Format("From server : {0}", myStr));
}
_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
}
//new
在Listener.cs中添加如下新函数
//new
public void Send(string s)
{
client.Send(s);
}
//new
在Client.cs中添加如下新函数
//new
public void Send(string s)
{
if (_Socket.Connected)
{
Byte[] byteData = Encoding.ASCII.GetBytes(s.ToCharArray());
_Socket.Send(byteData, byteData.Length, 0);
}
}
//new
在 ExampleServer.Program 中,修改您的 Main(string[] args) 函数
static void Main(string[] args)
{
int port = 5555;
Console.WriteLine(string.Format("Server Başlatıldı. Port: {0}", port));
Console.WriteLine("-----------------------------");
Listener listener = new Listener(port, 50);
listener.Start();
//new
bool dewamke = true;
while (dewamke)
{
Console.WriteLine("Write exit to close or write anything for sending data.");
var cmd = Console.ReadLine();
if (cmd == "exit")
dewamke = false;
else
listener.Send(cmd);
}
Console.WriteLine("closing server.");
Console.ReadLine();
//new
}
我用这段代码解决了 client.cs 中的问题:
void HandleReceivedData(byte[] resizedBuffer)
{
if (_OnExampleDTOReceived != null)
{
//using (var ms = new MemoryStream(resizedBuffer))
//{
// // BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate'e parametre olarak geçiyoruz.
// string exampleDTO = new BinaryFormatter().Deserialize(ms) as string;
// if (exampleDTO == "POSALIVE")
// SendData("ACK");
// _OnExampleDTOReceived(exampleDTO);
//}
using (MemoryStream stream = new MemoryStream(resizedBuffer))
{
stream.Position = 0;
var sr = new StreamReader(stream);
string myStr = sr.ReadToEnd();
if (myStr.Contains("POSALIVE"))
SendData("ACK");
_OnExampleDTOReceived(myStr);
}
}
}
public void SendData(string message)
{
using (var ms = new MemoryStream())
{
// İlgili object'imizi binary'e serialize ediyoruz.
new BinaryFormatter().Serialize(ms, message);
IList<ArraySegment<byte>> data = new List<ArraySegment<byte>>();
data.Add(new ArraySegment<byte>(ms.ToArray()));
// Gönderme işlemine başlıyoruz.
_Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
{
// Gönderme işlemini bitiriyoruz.
int length = _Socket.EndSend(asyncResult, out socketError);
if (length <= 0 || socketError != SocketError.Success)
{
log.append("Server bağlantısı koptu!", "");
return;
}
}, null);
if (socketError != SocketError.Success)
log.append("Server bağlantısı koptu!", "");
}
}
我在client.cs
中添加了发送数据方法