C# Socket网络编程
只要知道要通信的两台主机的IP地址和进程的端口号,然后可以用Socket让这两个进程进行通信。
在本机上运行服务端和客户端,ip为127.0.0.1,使用端口9050(0~1023的端口号通常用于一些比较知名的网络服务和应用,普通网络应用程序则应该使用1024以上的端口号,以避免该端口号被另一个应用或系统服务使用)。
服务端:
var ip = "127.0.0.1";
var port = 9050;
//第一步:建立一个用于通信的Socket对象
//参数1:指定该IP对应的协议,此为IPv4;参数2:定义要打开的Socket的类型;参数3:向Windows Sockets API通知所请求的协议
var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//第二步:使用bind绑定IP地址和端口号,IPEndPoint内参数为IPAddress的long类型和端口号
var ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
serverSocket.Bind(ipEndPoint);
//第三步:使用listen监听客户端,参数为指定侦听队列的容量
serverSocket.Listen(10);
//第四步:使用accept中断程序直到连接上客户端,(接收连接并返回一个新的Socket,Accept会中断程序,直到有客户端连接)
Console.WriteLine("等待客户端连接...");
var socket = serverSocket.Accept();
var socketip = (IPEndPoint) socket.RemoteEndPoint;
Console.WriteLine($"连接成功! ip:{socketip.Address} 端口:{socketip.Port}");
//第五步:接收来自客户端的请求,用死循环来不断的从客户端获取信息
while (true)
{
var receiveBytes = new byte[1024];
var receive = socket.Receive(receiveBytes);
if (receive == 0 || Encoding.UTF8.GetString(receiveBytes, 0, receive) == "exit") //当信息长度为0或收到exit,说明客户端连接断开
{
break;
}
Console.WriteLine(Encoding.UTF8.GetString(receiveBytes, 0, receive)); //将指定字节数组中的一个字节序列解码为一个字符串
}
//第六步:返回客户端的数据
var send = new byte[1024];
send = Encoding.UTF8.GetBytes("服务端已关闭!");
socket.Send(send);
//第七步:如果接收到客户端已关闭连接信息就关闭服务器端,并返回信息
serverSocket.Close();
socket.Close();
Console.WriteLine("服务端关闭...");
客户端:
var ip = "127.0.0.1";
var port = 9050;
//第一步:建立一个用于通信的Socket对象
var ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//第二步:根据指定的IP和端口连接服务器
//IPAddress:包含了一个IP地址;IPEndPoint:包含了一对IP地址(IPAdress类型)和端口号
var ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
ClientSocket.Connect(ipEndPoint);
//第三步:连接成功后向服务器端发送数据请求
while (true)
{
var send = new byte[1024];
Console.WriteLine("请输入要发送的数据:");
var str = Console.ReadLine();
send = Encoding.UTF8.GetBytes(str);
ClientSocket.Send(send);
if (str == "exit")
{
Console.WriteLine("已退出...");
break;
}
Console.WriteLine("发送成功!" + "\n");
}
//第四步:接收服务器返回的请求数据
var receiveBytes = new byte[1024];
var receive = ClientSocket.Receive(receiveBytes);
Console.WriteLine(Encoding.UTF8.GetString(receiveBytes, 0, receive));
//第五步:如果不需要请求数据就关闭客户端并给服务器发送关闭连接信息
ClientSocket.Close();
通讯:
public class CodeScanner_Socket : NotifyPropertyChanged
{
public Socket ClientSocket;
public string ip, port;
private string _ReceivedText = string.Empty;
private Task task;
private BackgroundWorker backgroundWorker;
private bool IsReceived = false;
public CodeScanner_Socket(string ip, string port)
{
this.ip = ip;
this.port = port;
}
/// <summary>
/// 接收到的数据
/// </summary>
public string ReceivedText
{
get => _ReceivedText;
set
{
_ReceivedText = value;
OnPropertyChanged();
}
}
/// <summary>
/// 判断是否已连接,true已连接;false未连接
/// </summary>
/// <returns></returns>
public virtual bool IsSocketConnected()
{
if (ClientSocket != null)
{
try
{
// 尝试发送一个空字节数组来检查连接
byte[] emptyBuffer = new byte[0];
ClientSocket.Send(emptyBuffer);
// 如果没有抛出异常,则可能认为Socket是连接的
return true;
}
catch (SocketException ex)
{
// 检查特定的错误代码
switch (ex.ErrorCode)
{
case (int)System.Net.Sockets.SocketError.ConnectionReset:
case (int)System.Net.Sockets.SocketError.ConnectionAborted:
case (int)System.Net.Sockets.SocketError.NotConnected:
// 这些错误通常表示连接已经断开
PlateLogOperator.Info($"Socket is not connected.\r\nCaught ErrorCode:{ex.ErrorCode}");
break;
default:
// 处理其他类型的SocketException
PlateLogOperator.Info("Socket exception occurred: " + ex.Message);
break;
}
return false;
}
}
return false;
}
/// <summary>
/// 连接
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="Port">端口号</param>
/// <returns></returns>
public virtual bool SocketConnect()
{
try
{
if (IsSocketConnected())
{
PlateLogOperator.Warn("已连接...");
return true;
}
var port_int = Convert.ToInt32(port);
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port_int);
ClientSocket.Connect(ipEndPoint);
//task = Task.Factory.StartNew(() =>
//{
// ClientReceived();
//}, TaskCreationOptions.LongRunning);
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += ClientReceived;
backgroundWorker.WorkerSupportsCancellation = true; //允许取消
backgroundWorker.RunWorkerAsync(); //开始执行DoWork
return true;
}
catch (Exception e)
{
PlateLogOperator.Error($"发生错误,原因:{e.Message} 位置:{e.StackTrace.Substring(e.StackTrace.Length - 6)}");
ClientSocket = null;
return false;
}
}
/// <summary>
/// 断开连接
/// </summary>
/// <returns></returns>
public virtual bool SocketDisConnect()
{
try
{
if (ClientSocket != null && IsSocketConnected())
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
ClientSocket = null;
return true;
}
return false;
}
catch (Exception e)
{
PlateLogOperator.Error(e.Message);
return false;
}
}
/// <summary>
/// 客户端发送数据,可重写
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public virtual bool ClientSend(string str)
{
try
{
var send = new byte[1024];
send = Encoding.UTF8.GetBytes(str);
//send = Encoding.ASCII.GetBytes(str);
if (ClientSocket != null && IsSocketConnected())
{
ClientSocket.Send(send);
}
else
{
PlateLogOperator.Warn("客户端未连接!!!");
return false;
}
return true;
}
catch (Exception e)
{
PlateLogOperator.Error(e.Message);
return false;
}
}
/// <summary>
/// 接收服务端传过来的数据
/// </summary>
public virtual void ClientReceived(object sender, DoWorkEventArgs e)
{
try
{
while (!backgroundWorker.CancellationPending)
{
if (ClientSocket.Poll(10, SelectMode.SelectRead))
{
backgroundWorker.CancelAsync(); //停止执行DoWork
break;
}
var buffer = new byte[4096];
var nRevBufCnt = ClientSocket.Receive(buffer);
if (nRevBufCnt <= 0)
break;
IsReceived = true;
ReceivedText = Encoding.UTF8.GetString(buffer, 0, nRevBufCnt);
}
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
ClientSocket = null;
}
catch (Exception ex)
{
//PlateLogOperator.Error("ClientReceived:" + ex.Message);
ClientSocket?.Shutdown(SocketShutdown.Both);
ClientSocket?.Close();
ClientSocket = null;
ReceivedText = null;
}
}
/// <summary>
/// 处理返回的数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="RtnMsg"></param>
/// <returns></returns>
public virtual string RtnMsgConvert()
{
if (IsReceived)
{
IsReceived = false;
return ReceivedText;
}
return string.Empty;
}
}