自定义SocketTcpServer,虽然现在有很多这样的组件,但是有时候还是需要把它集成在你的框架或者产品中,不需要特别强大的功能,根据需求定制。最基本的一个问题是判断数据包的结束,没有像supersocket那样默认以换行作为一个命令的结束,如果需要可以改善。

     public interface ISocketTcpServer
{
void Listen();
void Stop();
void SendData(byte[] data, Socket client); event ReceiveDataHandler ReceivedDataEvent;
event OnlineChangeHandler OnlineChangeEvent;
event ErrorHandler ErrorEvent;
} public delegate void ReceiveDataHandler(SocketState state); public delegate void OnlineChangeHandler(int onlines, EndPoint client); public delegate void ErrorHandler(string error, EndPoint client); public class SocketTcpServer : ISocketTcpServer
{
private readonly Socket _tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public readonly EndPoint LocalPoint;
public readonly List<SocketState> ClientList = new List<SocketState>();
public bool IsListening; public SocketTcpServer(IPEndPoint localPoint)
{
LocalPoint = localPoint;
} public void Listen()
{
_tcpSocket.Bind(LocalPoint);
_tcpSocket.Listen();
_tcpSocket.BeginAccept(AcceptClientCallBack, _tcpSocket);
IsListening = true;
} public void Stop()
{
IsListening = false;
foreach (var state in ClientList)
{
state.ClientSocket.Close();
}
ClientList.Clear();
_tcpSocket.Close();
OnlineChangeEvent?.Invoke(ClientList.Count, new IPEndPoint(IPAddress.Any, ));
} private void AcceptClientCallBack(IAsyncResult ar)
{
var server = ar.AsyncState as Socket;
if (IsListening && server != null)
{
try
{
var client = server.EndAccept(ar);
var clientState = new SocketState()
{
ClientSocket = client,
RemotePoint = client.RemoteEndPoint,
};
var tem = ClientList.FirstOrDefault(x => x.RemotePoint.Equals(clientState.RemotePoint));
if (tem != null)
{
tem.ClientSocket.Close();
ClientList.Remove(tem);
}
ClientList.Add(clientState);
BeginReveive(client);
OnlineChangeEvent?.Invoke(ClientList.Count, client.RemoteEndPoint);
}
catch (Exception error)
{
ErrorEvent?.Invoke(error.Message, null);
}
finally
{
server.BeginAccept(AcceptClientCallBack, server);
}
}
} private void BeginReveive(Socket client)
{
if (client.Connected)
{
var state = new SocketState()
{
ClientSocket = client,
RemotePoint = client.RemoteEndPoint,
};
client.BeginReceiveFrom(
state.Buffer,
,
state.Buffer.Length,
SocketFlags.None,
ref state.RemotePoint,
ReceiveCallback,
state);
}
} private void ReceiveCallback(IAsyncResult ar)
{
var state = ar.AsyncState as SocketState;
try
{
if (state != null && state.ClientSocket.Connected)
{
state.DataLen = state.ClientSocket.EndReceiveFrom(ar, ref state.RemotePoint);
if (state.DataLen == )
{
state.ClientSocket.Close();
var tem = ClientList.FirstOrDefault(x => x.RemotePoint.Equals(state.RemotePoint));
ClientList.Remove(tem);
OnlineChangeEvent?.Invoke(ClientList.Count, state.RemotePoint);
}
else
{
byte[] receivedData = new byte[state.DataLen];
Array.Copy(state.Buffer, , receivedData, , state.DataLen);
state.Buffer = receivedData;
ReceivedDataEvent?.Invoke(state);
}
}
}
catch (Exception error)
{
ErrorEvent?.Invoke(error.Message, state.RemotePoint);
state.ClientSocket.Close();
var tem = ClientList.FirstOrDefault(x => x.RemotePoint.Equals(state.RemotePoint));
ClientList.Remove(tem);
OnlineChangeEvent?.Invoke(ClientList.Count, state.RemotePoint);
}
finally
{
if (state != null) BeginReveive(state.ClientSocket);
}
} public void SendData(byte[] data, Socket client)
{
if (client.Connected)
{
var state = new SocketState()
{
ClientSocket = client,
RemotePoint = client.RemoteEndPoint,
Buffer = data,
DataLen = data.Length,
};
client.BeginSendTo(data, , data.Length, SocketFlags.None, state.RemotePoint, SendCallback, state);
}
} private void SendCallback(IAsyncResult ar)
{
var state = ar.AsyncState as SocketState;
try
{
if (state != null && state.ClientSocket.Connected)
{
state.ClientSocket.EndSendTo(ar);
}
}
catch (Exception error)
{
ErrorEvent?.Invoke(error.Message, state.RemotePoint);
}
} public event ReceiveDataHandler ReceivedDataEvent; public event OnlineChangeHandler OnlineChangeEvent; public event ErrorHandler ErrorEvent;
} public class SocketState
{
public byte[] Buffer = new byte[*];
public Socket ClientSocket;
public int DataLen;
public EndPoint RemotePoint;
}

SocketTcpServer的更多相关文章

  1. C#网络编程系列(两)它Socket同步TCPserver

    声明原文 笔者:竹zz  本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列文件夹 C#网络编程系列文 ...

  2. Unity C# 自定义TCP传输协议以及封包拆包、解决粘包问题

    本文只是初步实现了一个简单的TCP自定协议,更为复杂的协议可以根据这种方式去扩展. TCP协议,通俗一点的讲,它是一种基于socket传输的由发送方和接收方事先协商好的一种消息包组成结构,主要由消息头 ...

  3. QT创建TCP Socket通信

    最近在学习QT,了解到QT可以进行SOCKET网络通信,进行学习,并建立一个简单的聊天DEMO.为了测试是否能与VS2012下的程序进行通信,在VS2012下建立一个客户端程序,进行通信测试,发现可以 ...

  4. Android之socket服务端

    import java.io.DataInputStream; import java.io.IOException; import java.io.PrintWriter; import java. ...

  5. 8.9.网络编程_Socket 远程调用机制

    1.网络编程 1.1.网络编程概述: 通过通信线路(有线或无线)可以把不同地理位置且相互独立的计算机连同其外部设备连接起来,组成计算机网络.在操作系统.网络管理软件及网络 通信协议的管理和协调下,可以 ...

  6. 1、Socket通信

    [TCP] 服务器端:无目标插座升级为有目标插座后,就可以通过有目标的插座收发数据 客户端: 实战:此案例有利于理解Socket的工作流程. 缺点:服务器只能接收1个客户端的连接,因为只写了一个Acc ...

随机推荐

  1. Java 前后端分离研究

    https://github.com/ulyn/eos https://github.com/lenbo-ma/jfinal-api-scaffold/

  2. 在python中使用matplotlib中的Matplotlib-Animation “No MovieWriters Available”

    在使用官方的示例代码中,一部分使用了ffmpeg 在执行时会报如题一样的错误 解决: 下载windows的版本,解压,然后将bin目录加入系统环境变量的路径中 如:D:\Program Files\f ...

  3. oracle PROCEDURE AS IS区别

    在存储过程(PROCEDURE)和函数(FUNCTION)中没有区别,在视图(VIEW)中只能用 ,在游标(CURSOR)中只能用IS不能用AS.

  4. 【0 - 1】OC内存管理

    一.内存管理概述 垃圾回收机制(GC):由系统管理内存,程序员不需要管理. OC中的垃圾回收:在OC2.0版加入垃圾回收. OC与iOS:OC有垃圾回收机制,但是iOS屏蔽了这个功能.原因:iOS运行 ...

  5. Asp.net MVC 视图(三)

    Html辅助方法(HtmlHelper类) 可以通过视图的Html属性调用HTML辅助方法,也可以通过Url属性调用URL辅助方法,还可以通过Ajax属性调用Ajax辅助方法. 在控制器中也存在Url ...

  6. GSM模块fibocom G510使用记录

    一、背景:最近在做一个单定位的产品,对低功耗要求较高,选用了G510系列的模块。现在仅做了三块样板,先熟悉下。 二、优点:1.功耗低,和西门子的BGS2差不多;2.注册网络指令简单;3.其他有待发现 ...

  7. HTML特殊符号对照表

    特殊符号 命名实体 十进制编码 特殊符号 命名实体 十进制编码 Α Α Α Β Β Β Γ Γ Γ Δ Δ Δ Ε Ε Ε Ζ Ζ Ζ Η Η Η Θ Θ Θ Ι Ι Ι Κ Κ Κ Λ Λ Λ Μ ...

  8. UISegmentedControl的详细使用

    当用户输入不仅仅是布尔值时,可使用分段控件(UISegmentedControl).分段控件提供一栏按钮(有时称为按钮栏),但只能激活其中一个按钮.分段控件会导致用户在屏幕上看到的内容发生变化.它们常 ...

  9. AMQP与RabbitMQ简介

    MQ(Message Queue,消息队列)是一种应用系统之间的通信方法.是通过读写出入队列的消息来通信(RPC则是通过直接调用彼此来通信的). 1.AMQP协议 在了解RabbitMQ之前,首先要了 ...

  10. 1、datatable与datagrid之间的绑定

    1.前台代码: 插入一个datagrid控件,设置几列. 这里有两点要注意: 1)为了显示所要查询的日期,我将前台的列名与后台查询出来的日期绑定了,用了x:Name这个属性 2)与后台datatabl ...