{
public Service1()
{
InitializeComponent();
}
System.Timers.Timer timer;
private StreamWriter streamWriter; //写文件
Thread threadWatch = null; // 负责监听客户端连接请求的 线程;
Socket socketWatch = null;
private string host = ConfigurationManager.AppSettings[“ip”].ToString();
private int port = int.Parse(ConfigurationManager.AppSettings[“port”].ToString());
private int second = int.Parse(ConfigurationManager.AppSettings[“second”].ToString());
DBAll db = new DBAll();
protected override void OnStart(string[] args)
{
btnBeginListen();
timer = new System.Timers.Timer();
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = second * 1000;
timer.Enabled = true;
timer.Start();
}
protected override void OnStop()
{
WriteError(“服务已经停止了!”);
}
//socket开启
public void btnBeginListen()
{
// 创建负责监听的套接字
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress address = IPAddress.Parse(host);
// 创建包含ip和端口号的网络节点对象;
IPEndPoint endPoint = new IPEndPoint(address, port);
try
{
// 将负责监听的套接字绑定到唯一的ip和端口上;
socketWatch.Bind(endPoint);
}
catch
{
return;
}
// 设置监听队列的长度;
socketWatch.Listen(100);
// 创建负责监听的线程;
threadWatch = new Thread(WatchConnecting);
threadWatch.IsBackground = true;
threadWatch.Start();
//}
}
/// <summary>
/// 监听客户端请求的方法;
/// </summary>
void WatchConnecting()
{
while (true) // 持续不断的监听客户端的连接请求;
{
// 开始监听客户端连接请求,Accept方法会阻断当前的线程;
Socket sokConnection = socketWatch.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
// 客户端的IP信息;
// WriteError(sokConnection.RemoteEndPoint.ToString());
Thread thr = new Thread(RecMsg);
thr.IsBackground = true;
thr.Start(sokConnection);
}
}
/// <summary>
/// 接受信息的方法
/// </summary>
/// <param name=”sokConnectionparn”></param>
void RecMsg(object sokConnectionparn)
{
Socket sokClient = sokConnectionparn as Socket;
//List<byte> byteList = new List<byte>();
//int length = -1;
//do
//{
// // 定义一个1M的缓存区;
// byte[] arrMsgRec = new byte[1024];
// // 将接受到的数据存入到输入 arrMsgRec中;
// try
// {
// length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
// byteList.AddRange(arrMsgRec);
// if (length < byteList.ToArray().Length)
// {
// string strMsg = System.Text.Encoding.Default.GetString(byteList.ToArray(), 0, length);// 将接受到的字节数据转化成字符串;
// handleData(strMsg, sokClient);
// }
// }
// catch
// {
// break;
// }
//} while (true);
do
{
byte[] arrMsgRec = new byte[1024];
try
{
int length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
string strMsg = System.Text.Encoding.Default.GetString(arrMsgRec, 0, length);// 将接受到的字节数据转化成字符串;
handleData(strMsg, sokClient);
}
catch
{
break;
}
} while (true);
}
/// <summary>
/// 处理数据的方法
/// </summary>
public void handleData(string str, Socket sokClient)
{
string[] strAll = str.Split(” “);
switch (int.Parse(strAll[8]))
{
case 2://登陆
break;
case 1://心跳
heartbeat(str, sokClient);
break;
}
}
#region 心跳
public void heartbeat(string str, Socket sokClient)
{
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
}
#endregion
public void WriteError(string message)
{
try
{
string directPath = System.AppDomain.CurrentDomain.BaseDirectory + “info\”;
if (!Directory.Exists(directPath)) //判断文件夹能否存在,假如不存在则创建
{
Directory.CreateDirectory(directPath);
}
directPath += string.Format(@”\{0}.log”, DateTime.Now.ToString(“yyyy-MM-dd”));
if (streamWriter == null)
{
streamWriter = !File.Exists(directPath) ? File.CreateText(directPath) : File.AppendText(directPath); //判断文件能否存在假如不存在则创建,假如存在则添加。
}
streamWriter.WriteLine(“***********************************************************************”);
streamWriter.WriteLine(“错误时间:” + DateTime.Now.ToString(“HH:mm:ss”));
if (message != null)
{
streamWriter.WriteLine(“异常信息:\r\n” + message);
}
}
finally
{
if (streamWriter != null)
{
streamWriter.Flush();
streamWriter.Dispose();
streamWriter = null;
}
}
}
}
主要是心跳包的检测是检测哪个方法 或放在哪个位置啊?
50
第二,你的 handleData 方法本来就是处理各种消息的。刚一看你的问题描述,给本人说“蒙了”,本人说“这个人怎么会说通讯是到数据库表存数据”呢?看了你这个方法本人知道了,你根本没有搞懂本人写了什么代码。这里就是处理消息啊,你就按照你们的约定返回呗。例如说约定要返回“OK”,那么就向 sokClient 写入包含了“OK”的消息(的二进制编码)呗。
第三,不要滥用 Encoding.Default。这个在不同的机器上、不同的操作系统上,返回结果不同。所以用这个 Default,看上去挺高大上(通用),实际上是滥用,你根本不确定本人再干什么。所以使用 UTF8 或 gb2312 都可以,但是不要滥用 Default。
第四,handleData 通常应该异步多线程来实现,例如写
ThreadPool.QueueUserWorkItem(h =>handleData(strMsg, sokClient));
,这样可以释放 I/O 线程,从而让它提前处理 sokClient 的后边的消息。当然,这是假设你对于长连接的通讯方式,知道信令处理完然后返回结果的次序跟收到信令的次序可能有所改变的情况下。原因是有的任务可能处理要200毫秒,而有的可能只要3毫秒,那么当客户端以次序1、2、3、4、5来发送消息时,可能受到反馈的次序是对应着1、4、2、5、3消息的。
假如你不想处理长连接的业务逻辑,那么就不要写成一个长连接的通讯程序。
10
这对你有好处。
10
对于server来说,要管理的对象不能是个“裸”的socket,而是要抽象下,是基于socket的客户端session
这session中除了socket,大多数情况下还要记录身份验证信息,最后一次接收数据的时间等,
同时server侧要有超时剔除逻辑,当session的操作时间timeout后,
将相应的socket关闭,释放资源
10
10
8
1
1