网络同步校时TCP服务器端SDK代码(RFC868/C++/WIN32/SOCKET/TCP/select)

原创 2004年11月03日 19:38:00

//以下是一段服务器端SDK代码, 较简单, 稍加修改可应用于NT服务程序中
//仅供初学者参考, 高手勿入, 谢谢
#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#include <map>
#include <cassert>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <exception>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <tchar.h>
#include <ctime>
using namespace std;

#include <winsock2.h>
#include <windows.h>

#include "thread.h"//该文件见本文末
#include "threadpool.h"//见我的WIN32线程池文章

char * GetErrorMessage(char *szBuffer, DWORD dwSize)
{
 FormatMessage(
  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  NULL,
  GetLastError(),
  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  szBuffer,
  dwSize - 1,
  NULL
  );
 return szBuffer;
}

class RFC868TCPServer : public ThreadJob, public Thread
{
 SOCKET _S37;
 long _lWorkCount;
 bool _fRunFlag;
 u_long _uIP;
 ThreadPool _TP;
public:
 RFC868TCPServer(DWORD tp_num = 10) : _TP(tp_num), _S37(INVALID_SOCKET), _lWorkCount(0), _fRunFlag(true)
 {
  _uIP = htonl(INADDR_ANY); //默认监听IP为本地
 }
 ~RFC868TCPServer()
 {
  if(_S37 != INVALID_SOCKET)
   closesocket(_S37);
 }
 bool Begin()//开始监听并启动线程
 {
  char Buffer[256];
  struct sockaddr_in server;
  server.sin_family = AF_INET;
  server.sin_port = htons(37);
  server.sin_addr.s_addr = _uIP;

  if((_S37 = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
   return false;

  unsigned long  NonBlock = 1;
  if(ioctlsocket(_S37, FIONBIO, &NonBlock) == SOCKET_ERROR)
   return false;

  if(bind(_S37, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
   return false;

  if(listen(_S37, 20) == SOCKET_ERROR)
   return false;
  
  return Thread::Begin();
 }
 inline bool End()
 {
  _fRunFlag = false;
  Sleep(100);
  return Thread::End();
 }
 inline bool WaitEnd(DWORD dwWaitTime = INFINITE)
 {
  _fRunFlag = false;
  return !Wait(dwWaitTime) ? Thread::End() : true;
 }
 virtual void DoJob(void *para)//线程池的作业
 {
  SOCKET s = *(SOCKET *)para;
  delete para;
  
  time_t cur_time = time(NULL) + 2208988800;
  char s_buf[4], *tp = ((char *)&cur_time) + 3;
  for(int i=0; i<4; i++)
   s_buf[i] = *tp--;

  if(send(s, s_buf, 4, 0) == SOCKET_ERROR)
  {
   LogError();
   closesocket(s);
   return;
  }

  if(shutdown(s, SD_SEND) == SOCKET_ERROR)
  {
   LogError();
   closesocket(s); 
   return;
  }
  closesocket(s); 
  InterlockedIncrement(&_lWorkCount);
 }
 inline void LogMessage(char *szStr)
 {
  Thread::Lock();
  cout << szStr << endl;
  Thread::UnLock();
 }
 inline void LogError()
 {
  char Buffer[256];
  LogMessage(GetErrorMessage(Buffer, 256));
 }
 inline long GetWorkCount()
 {
  return  _lWorkCount;
 }
 inline void SetIP(char *szIPStr)
 {
  _uIP = inet_addr(szIPStr);
 }
 inline void SetIP(u_long ip)
 {
  _uIP = ip;
 }
 virtual void WorkProc()
 {
  char Buffer[500];
  SOCKET ns, s = _S37;

  struct sockaddr_in client;
  int len = sizeof(client), ret;

  FD_SET read_set;
  timeval tv = {0, 100000}; //tv.tv_sec = 0, tv.tv_usec = 100000;

  while(_fRunFlag)
  {
   FD_ZERO(&read_set);
   FD_SET(s, &read_set);

   ret = select(0, &read_set, NULL, NULL, &tv);//Selet模型

   if(ret == SOCKET_ERROR)
   {
    LogMessage(GetErrorMessage(Buffer, 500));
    continue;
   }

   if(FD_ISSET(s, &read_set))//等到客户端
   {
    ns = accept(s, (struct sockaddr *)&client, &len);
    if(ns != INVALID_SOCKET)
    {
     _TP.Call(this, new SOCKET(ns));//调用线程池
     sprintf(Buffer, "Accept Client %s (%d)/n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
     LogMessage(Buffer);
    }
    else
     LogMessage(GetErrorMessage(Buffer, 500));
   }
  }

  _TP.EndAndWait();
 }
};


int main(int argc, char *argv[])
{
 try
 {
  char Buffer[256];
  WORD wVersionRequested;
  WSADATA wsaData;
  wVersionRequested = MAKEWORD(2, 2);
  if(WSAStartup(wVersionRequested, &wsaData))
  {
   cout << __LINE__ << GetErrorMessage(Buffer, 256) << endl;
   return 1;
  }
  RFC868TCPServer tcp;
  if(!tcp.Begin())
   cout << __LINE__ << GetErrorMessage(Buffer, 256) << endl;
  for(;;)
  {
   Sleep(200);
   if(tcp.GetWorkCount() >= 5)//完成5客户端的时间发送就退出
    break;
  }
  tcp.WaitEnd();
  WSACleanup();
 }
 catch(exception &e)
 {
  cout << e.what() << endl;
 }
 return 0;
}
//------------------------------------------thread.h-------------------------------------------------
#ifndef _THREAD_H_
#define _THREAD_H_

#include <assert.h>
#include <windows.h>

class Thread
{
 typedef DWORD WINAPI ThreadProcType(LPVOID lpPara);
 static DWORD WINAPI DefaultThreadProc(LPVOID lpPara)
 {
  Thread *pThis = (Thread *)lpPara;
  pThis->WorkProc();
  return 0;
 }
 CRITICAL_SECTION _csBaseThreadLock;
protected:

 virtual void WorkProc()
 {
 }

 HANDLE _hThreadHandle;
 DWORD _dwThreadID;

public:
 Thread()
 {
  _hThreadHandle = NULL;
  InitializeCriticalSection(&_csBaseThreadLock);
 }
 ~Thread()
 {
  DeleteCriticalSection(&_csBaseThreadLock);
  if(!_hThreadHandle)
   CloseHandle(_hThreadHandle);
 }
 Thread(Thread&)
 {
  _hThreadHandle = NULL;
 }
 Thread& operator =(Thread& x)
 {
  return *this;
 }
 bool IsRunning()
 {
  return _hThreadHandle != NULL;
 }
 void Lock()
 {
  EnterCriticalSection(&_csBaseThreadLock);
 }
 void UnLock()
 {
  LeaveCriticalSection(&_csBaseThreadLock);
 }
 inline bool Begin(ThreadProcType ThreadProc = DefaultThreadProc)
 {
  if(!IsRunning())
   _hThreadHandle = CreateThread(NULL, 0, ThreadProc, this, 0, &_dwThreadID);

  return  IsRunning();
 };
 inline bool Begin(ThreadProcType ThreadProc , LPVOID lpPara)
 {
  if(!IsRunning())
   _hThreadHandle = CreateThread(NULL, 0, ThreadProc, lpPara, 0, &_dwThreadID);

  return  IsRunning();
 };
 inline bool End(DWORD dwEndCode = 0)
 {
  if(IsRunning())
  {
   if(!TerminateThread(_hThreadHandle, dwEndCode))
    return false;
   else
   {
    CloseHandle(_hThreadHandle);
    _hThreadHandle = NULL;
    return true;
   }
  }
  return false;
 }
 inline virtual bool Wait(DWORD dwWaitTime = INFINITE)
 {
  return IsRunning() ? WaitForSingleObject(_hThreadHandle, dwWaitTime) == WAIT_OBJECT_0 : false;
 }
 inline bool Suspend()
 {
  return IsRunning() ? SuspendThread(_hThreadHandle) != 0xFFFFFFFF : false;
 }
 inline bool Resume()
 {
  return IsRunning() ? ResumeThread(_hThreadHandle) != 0xFFFFFFFF : false;
 }
 inline int GetPriority()
 {
  assert(IsRunning());
  return GetThreadPriority(_hThreadHandle);
 }
 inline bool SetPriority(int iPriority)
 {
  assert(IsRunning());
  return SetThreadPriority(_hThreadHandle, iPriority);
 }
 inline const HANDLE GetThreadHandle()
 {
  return _hThreadHandle;
 }
 inline const DWORD GetThreadID()
 {
  return _dwThreadID;
 }
} ;

#endif //_THREAD_H_

网络同步校时客户端代码(RFC868/C++/WIN32/SOCKET)

大量的工业机肯定需要同步校时, 故去察看了RFC868, 我就试编了一个获得网络时间的小程序, 大家可以借鉴到自己的同步校时程序, 只是试验,所以程序结构并不严谨, 过一段时间我会把服务器段的代码贴出...
  • wujian53
  • wujian53
  • 2004年11月02日 18:23
  • 3430

网络同步校时UDP服务器端SDK代码(RFC868/C++/WIN32/SOCKET/UDP)

#pragma warning(disable: 4530)#pragma warning(disable: 4786)#include #include #include #include #inc...
  • wujian53
  • wujian53
  • 2004年11月04日 18:45
  • 1985

WIN SOCKET---TCP/IP代码 (win32程序)

//服务器端程序 #include #pragma comment(lib, "ws2_32.lib") //#pragma comment(lib,"ws2_32.lib")//否则...
  • berry666
  • berry666
  • 2012年08月20日 10:13
  • 2445

3个学习Socket编程的简单例子:TCP Server/Client, Select

      以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序。如果你能完全理解这3...
  • zhenjing
  • zhenjing
  • 2009年11月05日 10:24
  • 14902

C++服务器(六):socket 异步模型与select 的实现

之前在另一篇博客上提到一些关于socket 的异步模型的资料,其中有一篇博客写得很详细,在此附上链接: socket阻塞与非阻塞,同步与异步、I/O模型[1]这篇博客已经讲得很好了。但是我还是觉得...
  • u014613043
  • u014613043
  • 2016年04月07日 20:12
  • 3377

win32汇编实现一个简单的TCP服务端程序(WinSock的简单认知应用)

Windows网络编程,相信好多人都知道,但是我们一般都是用其他语言编写,例如C,C++,JAVA,python等等,这些语言都可以,但是汇编语言比较底层,利用它,我们可以更清晰的了解到网络编程的内在...
  • qq_22642239
  • qq_22642239
  • 2016年06月21日 19:27
  • 3459

C++ Socket 一个服务器 多个客户端 (阻塞式)

服务端 ServerNet.h#pragma once #include #include #include #include #include #include #include #incl...
  • qq_17543531
  • qq_17543531
  • 2016年08月11日 21:47
  • 4715

C++ 简单的 Tcp 实现[socket] 服务器端与客户端通信

 http://blog.csdn.net/guoguojune/archive/2011/02/15/6185301.aspx(原文的格式看着真叫一个舒服) 开发...
  • u011555996
  • u011555996
  • 2017年04月21日 17:09
  • 629

Android搭建简单的socket服务器——基于TCP

移动端基本上用http很多, 很少接触socket编程,对于在android端作为服务器更少,最近因为项目需要,要在android端搭建服务器,中转智能硬件发来的数据,所以写了个socket的简易服务...
  • mashoujun2012
  • mashoujun2012
  • 2017年04月21日 10:44
  • 2231

基于select模型的tcp服务器------一个服务器如何与多个客户端进行通信?

很多时候, 服务器都需要同时与多个客户端进行通信, 服务嘛, 就是这样。 下面, 我们用select模型来简要模拟一下这种情形。代码是最好的解释, 所以, 还是上代码吧:       服务端程序: #...
  • stpeace
  • stpeace
  • 2015年03月17日 22:00
  • 7603
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:网络同步校时TCP服务器端SDK代码(RFC868/C++/WIN32/SOCKET/TCP/select)
举报原因:
原因补充:

(最多只允许输入30个字)