基于C#的Socket通信

同步非阻塞 UDP

//声明全局引用
Socket UdpSocket;
Thread recvThread;
bool recvThreadStop;

//自动添加本地ip
string localhost = Dns.GetHostName();
IPAddress[] local_ip = Dns.GetHostAddresses(localhost);
foreach (IPAddress ip in local_ip)
{
    comboBox_IP.Items.Add(ip);
}

//实例化一个Socket对象,并绑定到指定端口
IPEndPoint Point;
Point = new IPEndPoint(IPAddress.Parse(comboBox_IP.Text), Convert.ToInt16(textBox_Port.Text));
UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UdpSocket.Bind(Point);

//实例化一个线程,用于接收远程数据
recvThread = new Thread(new ThreadStart(RecvData));
recvThreadStop = false;
recvThread.Start();

//线程的具体内容
private void RecvData()
{
    UdpSocket.Blocking = false;
    byte[] buffer = new byte[65536];
    EndPoint Point = new IPEndPoint(IPAddress.Any, 0);
    while (!recvThreadStop)
    {
        if (UdpSocket.Available == 0) continue;
        int count = UdpSocket.ReceiveFrom(buffer, ref Point);
        UdpSocket.SendTo(buffer, count, 0, Point);
    }
    UdpSocket.Close();
}

//向远程端口发送数据
IPEndPoint Point;
Point = new IPEndPoint(IPAddress.Parse(textBox_Remote.Text), Convert.ToInt16(textBox.Text));
byte[] sendData = Encoding.UTF8.GetBytes(textBox.Text);
UdpSocket.SendTo(sendData, Point);

//终止UDP传输
recvThreadStop = true;

同步非阻塞 TCP Client

//声明全局引用
Socket TcpSocket;
Thread recvThread;
bool recvThreadStop;

//自动添加本地ip
string localhost = Dns.GetHostName();
IPAddress[] local_ip = Dns.GetHostAddresses(localhost);
foreach (IPAddress ip in local_ip)
{
    comboBox_IP.Items.Add(ip);
}

//实例化一个Socket对象,并连接到服务端
IPEndPoint Point;
Point = new IPEndPoint(IPAddress.Parse(comboBox_IP.Text), Convert.ToInt16(textBox_Port.Text));
TcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
TcpSocket.Connect(Point);

//实例化一个线程,用于接收远程数据
recvThread = new Thread(new ThreadStart(RecvData));
recvThreadStop = false;
recvThread.Start();

//线程的具体内容
private void RecvData()
{
    byte[] buffer = new byte[65536];
    while (!recvThreadStop)
    {
        if (!TcpSocket.Poll(10, SelectMode.SelectRead)) continue;
        int count = TcpSocket.Receive(buffer);
        if (count > 0)
            TcpSocket.Send(buffer, count, SocketFlags.None);
        else break;
    }
    TcpSocket.Close();
}

//向远程端口发送数据
byte[] sendData = Encoding.UTF8.GetBytes(textBox.Text);
TcpSocket.Send(sendData);

//TCP断开连接
recvThreadStop = true;

同步非阻塞 TCP Server

//定义委托类型(回调函数类型)
delegate int AddItemCallBack(object item);
delegate void RemoveItemCallBack(object item);

//声明全局引用
Socket listenSocket;
Thread listenThread;
bool listenThreadStop;
AddItemCallBack addItemCallBack;
RemoveItemCallBack removeItemCallBack;
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

//自动添加本地ip
string localhost = Dns.GetHostName();
IPAddress[] local_ip = Dns.GetHostAddresses(localhost);
foreach (IPAddress ip in local_ip)
{
    comboBox.Items.Add(ip);
}

//实例化回调函数
addItemCallBack = comboBox.Items.Add;
removeItemCallBack = comboBox.Items.Remove;

//实例化一个Socket对象,并开始监听
IPEndPoint Point;
Point = new IPEndPoint(IPAddress.Parse(comboBox_IP.Text), Convert.ToInt16(textBox_Port.Text));
listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(Point);
listenSocket.Listen(10);

//实例化一个线程,用于监听客户端
listenThread = new Thread(new ThreadStart(Listening));
listenThreadStop = false;
listenThread.Start();

//父线程的具体内容
private void Listening()
{
    listenSocket.Blocking = false;
    while (!listenThreadStop)
    {
        try
        {
            Socket TcpSocket = listenSocket.Accept();
            string strPoint = TcpSocket.RemoteEndPoint.ToString();
            comboBox.Invoke(addItemCallBack, strPoint);
            dicSocket.Add(strPoint, TcpSocket);
            Thread recvThread = new Thread(new ParameterizedThreadStart(RecvData));
            recvThread.Start(TcpSocket);
        }
        catch { }
    }
    listenSocket.Close();
}

//子线程的具体内容
private void RecvData(object obj)
{
    Socket TcpSocket = obj as Socket;
    byte[] buffer = new byte[65536];
    while (!listenThreadStop)
    {
        if (!TcpSocket.Poll(10, SelectMode.SelectRead)) continue;
        int count = TcpSocket.Receive(buffer);
        if (count > 0)
            TcpSocket.Send(buffer, count, SocketFlags.None);
        else break;
    }
    comboBox.Invoke(removeItemCallBack, TcpSocket.RemoteEndPoint.ToString());
    dicSocket.Remove(TcpSocket.RemoteEndPoint.ToString());
    TcpSocket.Close();
}

//用字典实现向指定端口发送数据
string point = comboBox.SelectedItem.ToString();
byte[] sendData = Encoding.UTF8.GetBytes(textBox.Text);
dicSocket[point].Send(sendData);

//TCP断开连接
listenThreadStop = true;

异步(非阻塞) TCP Client

异步通常是非阻塞的

//用于在异步接收中传递信息的类
public class StateObject
{
    public const int BufferSize = 65536;
    public byte[] buffer = new byte[BufferSize];
    public Socket workSocket = null;
    public bool recvDone = true;
    public bool disconnect = false;
}

//声明全局引用
Socket TcpSocket;
bool recvStop;
static ManualResetEvent connectDone;

//自动添加本地ip
string localhost = Dns.GetHostName();
IPAddress[] local_ip = Dns.GetHostAddresses(localhost);
foreach (IPAddress ip in local_ip)
{
    comboBox_IP.Items.Add(ip);
}

//实例化一个Socket对象
IPEndPoint Point;
Point = new IPEndPoint(IPAddress.Parse(comboBox_IP.Text), Convert.ToInt16(textBox_Port.Text));
TcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//开始异步连接
recvStop = false;
connectDone = new ManualResetEvent(false);
TcpSocket.BeginConnect(Point, new AsyncCallback(ConnectCallback), TcpSocket);
connectDone.WaitOne();

//异步连接回调函数
private void ConnectCallback(IAsyncResult ar)
{
    Socket TcpSocket = (Socket)ar.AsyncState;
    TcpSocket.EndConnect(ar);
    connectDone.Set();

    StateObject state = new StateObject();
    state.workSocket = TcpSocket;
    while (!recvStop)
    {
        if (!state.recvDone) continue;
        if (state.disconnect) break;
        state.recvDone = false;
        TcpSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
                               new AsyncCallback(RecvCallback), state);
    }
    TcpSocket.Close();
}

//异步接收回调函数
private void RecvCallback(IAsyncResult ar)
{
    if (recvStop) return;
    StateObject state = (StateObject)ar.AsyncState;
    Socket TcpSocket = state.workSocket;
    int count = TcpSocket.EndReceive(ar);
    if (count > 0)
        TcpSocket.BeginSend(state.buffer, 0, count, 0, null, null);
    else
        state.disconnect = true;
    state.recvDone = true;
}

//向远程端口发送数据
byte[] sendData = Encoding.UTF8.GetBytes(textBox.Text);
TcpSocket.BeginSend(sendData, 0, sendData.Length, 0, null, null);

//TCP断开连接
recvThreadStop = true;

异步(非阻塞) TCP Server

异步通常是非阻塞的

//用于在异步接收中传递信息的类
public class StateObject
{
    public const int BufferSize = 65536;
    public byte[] buffer = new byte[BufferSize];
    public Socket workSocket = null;
    public bool recvDone = true;
    public bool disconnect = false;
}

//定义委托类型(回调函数类型)
delegate int AddItemCallBack(object item);
delegate void RemoveItemCallBack(object item);

//声明全局引用
Socket listenSocket;
Thread listenThread;
bool listenThreadStop;
AddItemCallBack addItemCallBack;
RemoveItemCallBack removeItemCallBack;
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

//自动添加本地ip
string localhost = Dns.GetHostName();
IPAddress[] local_ip = Dns.GetHostAddresses(localhost);
foreach (IPAddress ip in local_ip)
{
    comboBox.Items.Add(ip);
}

//实例化回调函数
addItemCallBack = comboBox.Items.Add;
removeItemCallBack = comboBox.Items.Remove;

//实例化一个Socket对象,并开始监听
IPEndPoint Point;
Point = new IPEndPoint(IPAddress.Parse(comboBox_IP.Text), Convert.ToInt16(textBox_Port.Text));
listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(Point);
listenSocket.Listen(10);

//实例化一个线程,用于监听客户端
listenThread = new Thread(new ThreadStart(Listening));
listenThreadStop = false;
listenThread.Start();

//线程的具体内容
private void Listening()
{
    while (!listenThreadStop)
    {
        if (!acceptDone) continue;
        acceptDone = false;
        listenSocket.BeginAccept(new AsyncCallback(AcceptCallback), listenSocket);
    }
    listenSocket.Close();
}

//异步连接回调函数
private void AcceptCallback(IAsyncResult ar)
{
    acceptDone = true;
    if (listenThreadStop) return;
    Socket listenSocket = (Socket)ar.AsyncState;
    Socket TcpSocket = listenSocket.EndAccept(ar);
    string strPoint = TcpSocket.RemoteEndPoint.ToString();
    comboBox.Invoke(addItemCallBack, strPoint);
    dicSocket.Add(strPoint, TcpSocket);

    StateObject state = new StateObject();
    state.workSocket = TcpSocket;
    while (!listenThreadStop)
    {
        if (!state.recvDone) continue;
        if (state.disconnect) break;
        state.recvDone = false;
        TcpSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
                               new AsyncCallback(RecvCallback), state);
    }
    comboBox.Invoke(removeItemCallBack, TcpSocket.RemoteEndPoint.ToString());
    dicSocket.Remove(TcpSocket.RemoteEndPoint.ToString());
    TcpSocket.Close();
}

//异步接收回调函数
private void RecvCallback(IAsyncResult ar)
{
    if (listenThreadStop) return;
    StateObject state = (StateObject)ar.AsyncState;
    Socket TcpSocket = state.workSocket;
    int count = TcpSocket.EndReceive(ar);
    if (count > 0)
        TcpSocket.BeginSend(state.buffer, 0, count, 0, null, null);
    else
        state.disconnect = true;
    state.recvDone = true;
}

//用字典实现向指定端口发送数据
string point = comboBox.SelectedItem.ToString();
byte[] sendData = Encoding.UTF8.GetBytes(textBox.Text);
dicSocket[point].BeginSend(sendData, 0, sendData.Length, 0, null, null);

//TCP断开连接
listenThreadStop = true;

总结:同步与异步

  1. 阻塞性的同步方法是当信号未到来之前会一直呈现成假死的状态。

  2. 非阻塞性的同步方法是当信号来了,还要自己去完成随后的相应处理。

  3. 异步方法是当信号来了并且随后的相应处理也结束了,才会去通知调用者。

意义:

  1. 异步操作可以减轻调用者所在线程的运算负担。(其次)
  2. 对于在信号到来后需要立刻做处理的情况,如果是同步操作,那么只能是新开一个线程来对信号的到来进行反复的轮询,而对于异步操作来说则可以采用硬件中断的方法来避免新开一个线程的资源。(首要)
  3. 线程间的切换会对系统产生额外的负担,过多的共享变量可能会导致死锁的出现。(未明)

缺点:Complicated

posted @ 2022-10-15 23:36  Kelvin-Wu  阅读(1018)  评论(0编辑  收藏  举报