我有一个使用TCP / IP协议监视Socket的Windows服务。根据我的要求,我的代码正在建立与机器的连接并从那里接收数据,这是我想要的,这就是为什么我已经做到了Windows服务。但我面临的问题是,该服务正在读取套接字端口3-4小时后自动停止从端口读取,而我的服务状态显示其运行。
这是我的Windows服务代码..
string ipaddress, textfileSaveLocation;
Byte[] bBuf;
string buf;
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private System.Threading.Thread _thread;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
string df = "";
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
_thread = new Thread(DoWork);
_thread.Start();
}
private void DoWork()
{
// create and monitor socket here...
ipaddress = "192.168.1.100";
int port = int.Parse("8181");
byte[] data = new byte[1024];
string stringData;
string input;
IPAddress ipadd = IPAddress.Parse(ipaddress);
IPEndPoint ipend = new IPEndPoint(ipadd, port);
sock.NoDelay = false;
try
{
sock.Connect(ipend);
}
catch (Exception dfg)
{
return;
}
try
{
input = "Client here";
sock.Send(Encoding.ASCII.GetBytes(input));
while (!_shutdownEvent.WaitOne(0))
{
data = new byte[1024];
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
}
}
catch (Exception DFGFD)
{
}
}
protected override void OnStop()
{
sock.Shutdown(SocketShutdown.Both);
sock.Close();
_shutdownEvent.Set();
_thread.Join(); // wait for thread to stop
}
}
}
为什么我的服务在3-4小时后停止接收数据?请帮我解决此问题。
这是我将ServerMachine数据插入文本文件的代码..
try
{
FileStream fs = new FileStream(textfileSaveLocation, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite);
StreamWriter swr = new StreamWriter(textfileSaveLocation,true);
swr.WriteLine(stringData);
swr.Close();
swr.Dispose();
fs.Close();
fs.Dispose();
}
catch (Exception Ex)
{
}
答案 0 :(得分:2)
正如@nobugz指出的,你有两个问题。
首先,您要吞下DoWork()
中发生的任何例外情况。你抓住它们,是的,但是你没有报告它们。几个小时后为什么会停止?好吧,服务器可能已关闭,这将终止您的套接字连接。您没有尝试重新连接,因此线程退出,但该过程继续运行。将一些异常报告放入以查看套接字关闭的原因,然后相应地处理它。
这导致了第二点,即你没有恢复能力。一旦发生异常或由于某种原因正常关闭套接字,您的线程就会退出。如果您希望这种方法能够持续工作,那么您需要添加在出现问题时尝试重新连接的逻辑。换句话说,DoWork()
退出的唯一原因是由于关闭事件。否则,它将需要循环,尝试在发生错误时重新连接。正如@nobugz所说,这还需要您重置ManualResetEvent
,以便在重新连接发生时,您的接收循环将按预期工作。但是,您无需在Reset()
回调中调用OnStart()
,因为您已将_shutdownEvent
初始化为false
,这是Reset()
的作用。
HTH。
这不在袖口,所以我不会验证它的准确性。我会解决你(或其他人)可能遇到的任何问题。
为关闭通知定义ManualResetEvent
对象。将OnStart()
回调更改为:
using System.Threading;
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
Thread _thread;
protected override void OnStart(string[] args)
{
// Create the thread and start it.
_thread = new Thread(DoWork);
_thread.Start();
}
由于您需要TCP连接,我强烈建议您使用TcpClient
而不是Socket
。将您的DoWork()
回调更改为以下内容:
using System.Net.Sockets;
private void DoWork()
{
while (!_shutdownEvent.WaitOne(0))
{
TcpClient client = new TcpClient();
try
{
// This is a blocking call. You might want to consider one of the
// asynchronous methods...
client.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.100"), 8181));
}
catch (Exception ex)
{
// Log the error here.
client.Close();
continue;
}
try
{
using (NetworkStream stream = client.GetStream())
{
byte[] notify = Encoding.ASCII.GetBytes("Client here");
stream.Write(notify, 0, notify.Length);
byte[] data = new byte[1024];
while (!_shutdownEvent.WaitOne(0))
{
int numBytesRead = stream.Read(data, 0, data.Length);
if (numBytesRead > 0)
{
string msg = Encoding.ASCII.GetString(data, 0, numBytesRead);
}
}
}
}
catch (Exception ex)
{
// Log the error here.
client.Close();
}
}
}
最后,在OnStop()回调中,触发线程关闭:
protected override void OnStop()
{
_shutdownEvent.Set(); // trigger the thread to stop
_thread.Join(); // wait for thread to stop
}
现在,了解TCP通信是基于流的非常重要。这意味着每次读取套接字时都不能保证收到完整的消息(例如TcpClient
)。如果服务器发回消息"收到客户端通知" ,最初读取套接字可能只会获得"客户端通知" 。随后的阅读可能会得到" fication recei" 。第三次阅读可能会得到" ved" 。您可以将读取缓冲在一起然后处理消息。大多数协议将使用某种标头来指示消息的类型和长度。如果您只是简单地使用字符串,那么消息的类型就不重要了,因为所有内容都是字符串。此外,知道字符串结束的位置可以使用空终止符来完成,而不是例如预先设置长度。只要知道,读取TCP套接字可能只会获得您希望接收的部分消息。