一直监听并接受指定端口的数据

xifengy 2008-03-12 11:01:07
我要实现多线程的服务端 接收端口数据
首先 监听端口 当过来一个连接
创建一个接收线程
hThread=CreateThread(NULL,NULL,AnswerThread,(LPVOID)AcceptSocket,0,&dwThreadId);

接收线程AnswerThread:
SOCKET ClientSocket=(SOCKET)(LPVOID)lparam;
byte recvbuf[1024]="";
for(;;)
{ //Receiving Data
bytesRecv=recv(ClientSocket,(char*)recvbuf,1024,0);
if(bytesRecv==SOCKET_ERROR) break;
//这里是数据的操作
}

我的问题:

当客户端连接并发送数据时正常,当如果关闭客户端后,这个for(;;) 会不停的执行刚才接收到的数据的操作,而不是正常退出,请问该如何处理?


另外,定义线程时,用
DWORD WINAPI AnswerThread(LPVOID lparam)

static VOID AnswerThread(LPVOID Parameter)
有什么区别?
...全文
270 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
xifengy 2008-04-26
  • 打赏
  • 举报
回复
void WINAPI ServiceMain()
{
// Register the control request handler
status.dwCurrentState = SERVICE_START_PENDING;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;

//注册服务控制
hServiceStatus = RegisterServiceCtrlHandler(szServiceName, ServiceStrl);
if (hServiceStatus == NULL)
{
LogEvent(_T("Handler not installed"));
return;
}
SetServiceStatus(hServiceStatus, &status);

status.dwWin32ExitCode = S_OK;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
status.dwCurrentState = SERVICE_RUNNING;
//SetServiceStatus(hServiceStatus, &status);


if(SetServiceStatus(hServiceStatus, &status)) OpenListen("");






status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hServiceStatus, &status);
LogEvent(_T("Service stopped"));


}

//*********************************************************
//Functiopn: ServiceStrl
//Description: 服务控制主函数,这里实现对服务的控制,
// 当在服务管理器上停止或其它操作时,将会运行此处代码
//Calls:
//Called By:
//Table Accessed:
//Table Updated:
//Input: dwOpcode:控制服务的状态
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
void WINAPI ServiceStrl(DWORD dwOpcode)
{
switch (dwOpcode)
{
case SERVICE_CONTROL_STOP:
status.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(hServiceStatus, &status);
PostThreadMessage(dwThreadID, WM_CLOSE, 0, 0);
break;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_SHUTDOWN:
break;
default:
LogEvent(_T("Bad service request"));
}
}
//*********************************************************
//Functiopn: IsInstalled
//Description: 判断服务是否已经被安装
//Calls:
//Called By:
//Table Accessed:
//Table Updated:
//Input:
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
BOOL IsInstalled()
{
BOOL bResult = FALSE;

//打开服务控制管理器
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (hSCM != NULL)
{
//打开服务
SC_HANDLE hService = ::OpenService(hSCM, szServiceName, SERVICE_QUERY_CONFIG);
if (hService != NULL)
{
bResult = TRUE;
::CloseServiceHandle(hService);
}
::CloseServiceHandle(hSCM);
}
return bResult;
}

//*********************************************************
//Functiopn: Install
//Description: 安装服务函数
//Calls:
//Called By:
//Table Accessed:
//Table Updated:
//Input:
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
BOOL Install()
{
if (IsInstalled())
return TRUE;

//打开服务控制管理器
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
MessageBox(NULL, _T("Couldn't open service manager"), szServiceName, MB_OK);
return FALSE;
}

// Get the executable file path
TCHAR szFilePath[MAX_PATH];
::GetModuleFileName(NULL, szFilePath, MAX_PATH);

//创建服务
SC_HANDLE hService = ::CreateService(
hSCM, szServiceName, szServiceName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, _T(""), NULL, NULL);

if (hService == NULL)
{
::CloseServiceHandle(hSCM);
MessageBox(NULL, _T("Couldn't create service"), szServiceName, MB_OK);
return FALSE;
}

::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);
return TRUE;
}

//*********************************************************
//Functiopn: Uninstall
//Description: 删除服务函数
//Calls:
//Called By:
//Table Accessed:
//Table Updated:
//Input:
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
BOOL Uninstall()
{
if (!IsInstalled())
return TRUE;

SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (hSCM == NULL)
{
MessageBox(NULL, _T("Couldn't open service manager"), szServiceName, MB_OK);
return FALSE;
}

SC_HANDLE hService = ::OpenService(hSCM, szServiceName, SERVICE_STOP | DELETE);

if (hService == NULL)
{
::CloseServiceHandle(hSCM);
MessageBox(NULL, _T("Couldn't open service"), szServiceName, MB_OK);
return FALSE;
}
SERVICE_STATUS status;
::ControlService(hService, SERVICE_CONTROL_STOP, &status);

//删除服务
BOOL bDelete = ::DeleteService(hService);
::CloseServiceHandle(hService);
::CloseServiceHandle(hSCM);

if (bDelete)
return TRUE;

LogEvent(_T("Service could not be deleted"));
return FALSE;
}

//*********************************************************
//Functiopn: LogEvent
//Description: 记录服务事件
//Calls:
//Called By:
//Table Accessed:
//Table Updated:
//Input:
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
void LogEvent(LPCTSTR pFormat, ...)
{
TCHAR chMsg[256];
HANDLE hEventSource;
LPTSTR lpszStrings[1];
va_list pArg;

va_start(pArg, pFormat);
_vstprintf(chMsg, pFormat, pArg);
va_end(pArg);

lpszStrings[0] = chMsg;

hEventSource = RegisterEventSource(NULL, szServiceName);
if (hEventSource != NULL)
{
ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL);
DeregisterEventSource(hEventSource);
}
}
xifengy 2008-04-26
  • 打赏
  • 举报
回复

//入口函数
void OpenListen(LPVOID Parameter)
{


conndb();



erroroutput("服务已经开始执行");
Sleep(1000);
WSADATA wsaData;
int iRet=WSAStartup(MAKEWORD(2,2),&wsaData);
if(iRet!=NO_ERROR)
{
erroroutput("wsastartup失败");
return;
}
SOCKET m_socket;
m_socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(m_socket==INVALID_SOCKET)
{
erroroutput("socket创建失败");
WSACleanup();
return ;
}

//创建一个端口

//找到本机IP

char HostName[80];
LPHOSTENT lpHostEnt;
struct in_addr addr;
if(gethostname(HostName,sizeof(HostName))==SOCKET_ERROR)
{ // 得到本主机名
erroroutput("获取主机名失败");
return;
}
lpHostEnt=gethostbyname(HostName);//利用得到的主机名去获得主机结构
if(!lpHostEnt)
{
erroroutput("获取IP失败");
return ;
}


memcpy(&addr,lpHostEnt->h_addr_list[0],sizeof(in_addr));

CString myip=inet_ntoa(addr);

sockaddr_in service;
service.sin_family=AF_INET;
service.sin_addr.s_addr=inet_addr(myip);
service.sin_port=htons(PORT);

if(bind(m_socket,(SOCKADDR*)&service,sizeof(service))==SOCKET_ERROR)
{
erroroutput("端口创建失败");

closesocket(m_socket);
return ;
}
else
{


}

//监听一个连接
if(listen(m_socket,SOMAXCONN)==SOCKET_ERROR)
erroroutput("端口监听失败");
else
erroroutput(myip+"上的端口创建成功,现已开始监听端口");

//accept a connection
SOCKET AcceptSocket;

//开始等待连接
while(1)
{
socketdb tsocket;

int addrlen;
addrlen=sizeof(tsocket.name);

AcceptSocket=SOCKET_ERROR;
while(AcceptSocket==SOCKET_ERROR)
{
AcceptSocket=accept(m_socket,(struct sockaddr *)&tsocket.name,&addrlen);

}

tsocket.socketname=AcceptSocket;


DWORD dwThreadId;
HANDLE hThread;

hThread=CreateThread(NULL,NULL,AnswerThread,(LPVOID)&tsocket,0,&dwThreadId);
if(hThread==NULL)
{
erroroutput("创建接受线程失败");
}
else
{
// erroroutput("创建接受线程成功" );

}
}
return ;





closeconn();
Sleep(1000000000);

//启动线程

}


//以下是服务函数,系统自动生成,ServiceMain为服务入口函数
//*********************************************************
//Functiopn: Init
//Description: 初始化
//Calls: main
//Called By:
//Table Accessed:
//Table Updated:
//Input:
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
void Init()
{
hServiceStatus = NULL;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
status.dwCurrentState = SERVICE_STOPPED;
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
status.dwWin32ExitCode = 0;
status.dwServiceSpecificExitCode = 0;
status.dwCheckPoint = 0;
status.dwWaitHint = 0;
}




//*********************************************************
//Functiopn: ServiceMain
//Description: 服务主函数,这在里进行控制对服务控制的注册
//Calls:
//Called By:
//Table Accessed:
//Table Updated:
//Input:
//Output:
//Return:
//Others:
//History:
// <author>niying <time>2006-8-10 <version> <desc>
//*********************************************************
xifengy 2008-04-26
  • 打赏
  • 举报
回复
我写出来了,程序给大家参考一下:


// ServiceTest.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "stdio.h"
#include "tchar.h"
#include <afxsock.h>
#include <afxdb.h>
//#include <afxdao.h>
#include <vector>

#include <afxmt.h>

//自定义内容:


#define PORT 34567
#define SIZEFILE 51200


CString m_strUser="sa";
CString m_strPwd="123456";
bool m_fConnected;
_ConnectionPtr m_pCon;
CString m_strSource="Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=gprsdata;Data Source=local";
CString m_strStepName;
_RecordsetPtr m_pRst;


CCriticalSection critical_section; //定义全局临界区

typedef struct socketdb{
SOCKET socketname;
struct sockaddr_in name;

}socketdb;

typedef struct sqldata{
VARIANT blobdata;
CString tip;
u_short tport;
}sqldata;


CWinThread *pThreadLisen; //监听线程-->_ListenTcpThread


//定义全局函数变量





void Init();
BOOL IsInstalled();
BOOL Install();
BOOL Uninstall();
void LogEvent(LPCTSTR pszFormat, ...);
void WINAPI ServiceMain();
void WINAPI ServiceStrl(DWORD dwOpcode);

//以下部分是服务系统函数,无需修改

TCHAR szServiceName[] = _T("ServiceTest");
BOOL bInstall;
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;
DWORD dwThreadID;




int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
Init();

dwThreadID = ::GetCurrentThreadId();

SERVICE_TABLE_ENTRY st[] =
{
{ szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};

if (stricmp(lpCmdLine, "/install") == 0)
{
Install();
}
else if (stricmp(lpCmdLine, "/uninstall") == 0)
{
Uninstall();
}
else
{
if (!::StartServiceCtrlDispatcher(st))
{
LogEvent(_T("Register Service Main Function Error!"));
}
}

return 0;
}

//下面开始主程序部分

//日志记录函数
void erroroutput(CString errorinfo)
{
CString time;
CString time2;
//CTime tm = CTime::GetCurrentTime();
SYSTEMTIME tm;
GetSystemTime(&tm);


time.Format(_T("%d-%d-%d %d:%d:%d:%d"),tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond,tm.wMilliseconds);
time2.Format(_T("%d%d%d%d%d%d%d"),tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond,tm.wMilliseconds);

CString filename;
filename="c:\\gprserror"+time2+".log";
CFile f;
CFileFind ff;
CString sFile =filename ;
if(!ff.FindFile(sFile, 0))
{
f.Open(sFile.GetBuffer(1),CFile::modeCreate,NULL);
f.Close();
}
//char oldstring[1024];
// f.Read(&oldstring,1024);

f.Open(sFile.GetBuffer(1),CFile::modeReadWrite);

CString outputstr;




outputstr=time+"收到消息"+"\r\n"+errorinfo+"\r\n";


f.Write(outputstr.GetBuffer(0),outputstr.GetLength());
f.Close();
ff.Close();
}


//信息写入文件函数

void AddFile(byte bbuffer[]) //将接收到的二进制数组写入为二进制文件
{
SYSTEMTIME tm;
GetSystemTime(&tm);
CString time;
time.Format(_T("%d%d%d%d%d%d%d"),tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond,tm.wMilliseconds);
CString filename;



filename="c:\\data"+time+".db";
CFile f;
CFileFind ff;
CString sFile =filename ;
if(!ff.FindFile(sFile, 0))
{
f.Open(sFile.GetBuffer(1),CFile::modeCreate,NULL);
f.Close();
}

f.Open(sFile.GetBuffer(1),CFile::modeReadWrite);


//int j,*pj;
//for(j=0;j<1024;j++) //以字节为单位的写入
//{
//写入数据
// pj->j

byte *pj=bbuffer;
f.Write(pj,SIZEFILE);


//HANDLE *WriteCounter;
//WriteFile((HANDLE)sFile,bbuffer,1024,this,0);
//}

f.Close();
ff.Close();



}


int conndb()
{
::CoInitialize(NULL); // 初始化OLE/COM库环境
m_fConnected=false;
try{
m_pCon.CreateInstance(__uuidof(Connection));
m_pCon->Open((_bstr_t)m_strSource,(_bstr_t)m_strUser,(_bstr_t)m_strPwd,adConnectUnspecified);
m_fConnected=true;
}
catch(_com_error e){

return -1;
}

return 0;
}

int closeconn()
{
if(!m_fConnected)return -1;
m_pCon->Close();
return 0;
}



int insertdb(byte bbuffer[],CString ip,u_short port,int bytesRecv)
{


byte *pbbuffer=bbuffer;

long nSize=bytesRecv;
VARIANT varBLOB;
SAFEARRAY * psa;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = nSize;
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
for(long i = 0; i < (long)nSize; i++)
SafeArrayPutElement(psa, &i, pbbuffer++);
varBLOB.vt = VT_ARRAY | VT_UI1;
varBLOB.parray = psa;

_RecordsetPtr prst=NULL;
_CommandPtr m_pCmd;
prst.CreateInstance(__uuidof(Recordset));
m_pCmd.CreateInstance(__uuidof(Command));
CString strSql;
CString teststr="aa";
CString tdata;
CString tip=ip;
u_short tport=port;

CTime tm = CTime::GetCurrentTime();
tdata.Format(_T("%d-%d-%d %d:%d:%d"),tm.GetYear(),tm.GetMonth(),tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());

//数据库锁定
critical_section.Lock();

try
{
prst->Open("logfiles",_variant_t((IDispatch *)m_pCon,true),adOpenKeyset,adLockOptimistic,adCmdTable);
//打开一个数据表
prst->AddNew();
prst->Fields->GetItem("datablob")->AppendChunk(varBLOB);
prst->Fields->GetItem("gettime")->Value=_bstr_t(tdata);
prst->Fields->GetItem("ip")->Value=_bstr_t(tip);
prst->Fields->GetItem("port")->Value=_bstr_t(tport);
prst->Fields->GetItem("databyte")->Value=_bstr_t(nSize);



::VariantClear(&varBLOB);
::SafeArrayDestroyData(psa);


prst->Update();
prst->Close();

erroroutput("添加成功!");
}
catch(_com_error e)
{

erroroutput("操作异常或者是你所在的用户组无此权限!");
Sleep(1000);
}

critical_section.Unlock();
//解锁


return 0;
}


//线程
DWORD WINAPI AnswerThread(LPVOID lparam)
{
socketdb *clientsocketsc=(socketdb *)lparam;
SOCKET ClientSocket=clientsocketsc->socketname;

CString tip=inet_ntoa(clientsocketsc->name.sin_addr);
u_short port=ntohs(clientsocketsc->name.sin_port);



int bytesRecv;
byte recvbuf[SIZEFILE]="";


//加入BLOB类型的数据
CString reslut="";
int insertok=0;
while( bytesRecv != SOCKET_ERROR && insertok==0)
{ //Receiving Data

bytesRecv=recv(ClientSocket,(char *)recvbuf,sizeof(recvbuf),0);
if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET )
{
erroroutput("连接断开");
break;
}


AddFile(recvbuf);
insertok=-1;

// insertok=insertdb(recvbuf,tip,port,bytesRecv);
if(bytesRecv==3 && recvbuf[0]==0x61 && recvbuf[1]==0x61 && recvbuf[2]==0x61 )
{
erroroutput("开始等待2分钟");
Sleep(120000);
}



}



//Write your processing code here


return 0;
ExitThread(0);
}



  • 打赏
  • 举报
回复
你打印每次recv的返回值看看。
如果客户端出错应该返回-1才对。

1,317

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧