很多时候我们要开发 服务器程序应用linux 和windows平台,很多时候得两套开发代码。我这里选择跨平台开发,已经在windows7 和 ubuntu 12.04 下,经
过测试,windows 称服务,linux称守护进程, 本质都是一样。
如果对服务守护进程不是很了解,可以参考【linux c 速学笔记】/【守护进程与socket编程】一章 ttp://www.cnblogs.com/wolfrickwang/p/3192949.html
关于命名规范问题,由于本程序在windows 平台下面编写,linux 下面测试 所以命名规范偏向windows 平台开发惯用命名规范。
现将代码张贴如下:
(1)公共头文件源码 server.h
#ifndef _SERVER_H_ #define _SERVER_H_ #ifdef WIN32 //Windows下定义 #include <winsock.h> #define Linux_Win_SOCKET SOCKET //定义Socket套接字变量类型 #define Linux_Win_CloseSocket closesocket #define Linux_Win_F_INET AF_INET //协议族命名约定 #define Linux_Win_InvalidSocket INVALID_SOCKET //非法的socket表示值定义 #define Linux_Win_SocketError SOCKET_ERROR //标准socket错误返回码 #define Linux_Win_SetSockOptArg4UseType const char //setsockopt第4个变量类型定义 #define Linux_Win_GetSockOptArg4UseType char //getsockopt第4个变量类型定义 #define Linux_Win_SendRecvLastArg 0 //send recv函数的最后一个参数类型 //注意此处,所有的错误返回码定名,Windows平台向向标准的伯克利socket规范靠拢。 #define EWOULDBLOCK WSAEWOULDBLOCK //10035 #define EINPROGRESS WSAEINPROGRESS #define EALREADY WSAEALREADY #define ENOTSOCK WSAENOTSOCK #define EDESTADDRREQ WSAEDESTADDRREQ #define EMSGSIZE WSAEMSGSIZE #define EPROTOTYPE WSAEPROTOTYPE #define ENOPROTOOPT WSAENOPROTOOPT #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #define EOPNOTSUPP WSAEOPNOTSUPP #define EPFNOSUPPORT WSAEPFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #define EADDRINUSE WSAEADDRINUSE #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define ENETDOWN WSAENETDOWN #define ENETUNREACH WSAENETUNREACH #define ENETRESET WSAENETRESET #define ECONNABORTED WSAECONNABORTED//10053 #define ECONNRESET WSAECONNRESET //10054 #define ENOBUFS WSAENOBUFS #define EISCONN WSAEISCONN #define ENOTCONN WSAENOTCONN #define ESHUTDOWN WSAESHUTDOWN #define ETOOMANYREFS WSAETOOMANYREFS #define ETIMEDOUT WSAETIMEDOUT #define ECONNREFUSED WSAECONNREFUSED #define ELOOP WSAELOOP #define EHOSTDOWN WSAEHOSTDOWN #define EHOSTUNREACH WSAEHOSTUNREACH #define EPROCLIM WSAEPROCLIM #define EUSERS WSAEUSERS #define EDQUOT WSAEDQUOT #define ESTALE WSAESTALE #define EREMOTE WSAEREMOTE #else //Linux下定义 #define Linux_Win_SOCKET int //定义Socket套接字变量类型 #define Linux_Win_CloseSocket close #define Linux_Win_F_INET AF_INET //协议族命名约定 #define Linux_Win_InvalidSocket -1 //非法的socket表示值定义 #define Linux_Win_SocketError -1 //标准socket错误返回码 #define Linux_Win_SetSockOptArg4UseType void //setsockopt第4个变量类型定义 #define Linux_Win_GetSockOptArg4UseType void //getsockopt第4个变量类型定义 #define Linux_Win_SendRecvLastArg MSG_NOSIGNAL //send recv函数的最后一个参数类型 #define Sleep(ms) usleep(ms*1000) #endif #endif
(二) 服务器端代码 server.c
/******************************** @跨平台开发服务测试 ********************************/ #ifdef WIN32 #include <windows.h> #include <winioctl.h> #include <tchar.h> #define UPDATE_TIME 1000*3 static LPWSTR serviceName = _T("SERVER"); static SERVICE_STATUS hServStatus; static SERVICE_STATUS_HANDLE hSStat; #else #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #endif #include "server.h" static int g_ServeExit = 0; //entry int ServerEntry(void); #ifdef WIN32 void UpServiceStatus (int NewStatus, int Check) { if (Check < 0 ) { hServStatus.dwCheckPoint++; } else { hServStatus.dwCheckPoint = Check; } if (NewStatus >= 0) { hServStatus.dwCurrentState = NewStatus; } if (!SetServiceStatus (hSStat, &hServStatus)) { hServStatus.dwCurrentState = SERVICE_STOPPED; hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; hServStatus.dwServiceSpecificExitCode = 2; UpServiceStatus (SERVICE_STOPPED, -1); return; } } void WINAPI ServerCtrlHandler(DWORD dwControl) { switch (dwControl) { case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: g_ServeExit = 1; UpServiceStatus (SERVICE_STOP_PENDING, -1); break; // case SERVICE_CONTROL_PAUSE: // break; // case SERVICE_CONTROL_CONTINUE: // break; // case SERVICE_CONTROL_INTERROGATE: // break; default: break; } UpServiceStatus(-1, -1); return; } void WINAPI ServiceMain (DWORD argc, LPWSTR *lpServiceArgVectors ) // char *argv[]) { hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; hServStatus.dwCurrentState = SERVICE_START_PENDING; hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; hServStatus.dwWin32ExitCode = NO_ERROR; hServStatus.dwServiceSpecificExitCode = 0; hServStatus.dwCheckPoint = 0; hServStatus.dwWaitHint = 2 * UPDATE_TIME; hSStat = RegisterServiceCtrlHandler( serviceName, ServerCtrlHandler); if (hSStat == 0) { hServStatus.dwCurrentState = SERVICE_STOPPED; hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; hServStatus.dwServiceSpecificExitCode = 1; UpServiceStatus (SERVICE_STOPPED, -1); return; } SetServiceStatus (hSStat, &hServStatus); //Entry server if (ServerEntry ()!= 0) { hServStatus.dwCurrentState = SERVICE_STOPPED; hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; hServStatus.dwServiceSpecificExitCode = 1; /* Server initilization failed */ SetServiceStatus (hSStat, &hServStatus); return; } UpServiceStatus(SERVICE_STOPPED, 0); return ; } #else void InitDaemon(void) { int pid; int i; if(pid=fork()) exit(0); //是父进程,结束父进程 else if(pid< 0) exit(1); //fork失败,退出 //是第一子进程,后台继续执行 setsid(); //第一子进程成为新的会话组长和进程组长 //并与控制终端分离 if(pid=fork()) exit(0); //是第一子进程,结束第一子进程 else if(pid< 0) exit(1); //fork失败,退出 //是第二子进程,继续 //第二子进程不再是会话组长 for(i=0;i< NOFILE;++i) //关闭打开的文件描述符 close(i); chdir("/tmp"); //改变工作目录到/tmp umask(0); //重设文件创建掩模 return; } LinuxCreateServer() { InitDaemon(); ServerEntry(); } #endif //the main int main(int argc, char* argv[]) { #ifdef WIN32 SERVICE_TABLE_ENTRY ServiceTable[]= { {serviceName,ServiceMain}, {NULL,NULL} }; #endif if (argc == 1 ) //server entry has no param { #ifdef WIN32 StartServiceCtrlDispatcher(ServiceTable); #else LinuxCreateServer(); #endif } else //no server for Debug mode { ServerEntry(); } return 0; } /************************************************************* @ @ @ *************************************************************/ #ifdef WIN32 //win32 #pragma comment(lib,"wsock32") //dll库调用准备 #endif void Linux_Win_Init() //win 32 socket初始化代码 { #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2 ); WSAStartup( wVersionRequested, &wsaData ); #endif } void Linux_Win_Exit() //win32 socket结束代码 { #ifdef WIN32 WSACleanup( ); #endif } #define MAX_CLIENT 30 #define SERVER_PORT 8111 #define SOSKET_BUFSIZE 1024 //entry the server int ServerEntry(void) { Linux_Win_SOCKET socketServer; Linux_Win_SOCKET socketChild; struct sockaddr_in serveDdr; struct sockaddr_in clildDdr; int socketAddLen; char buf[SOSKET_BUFSIZE] = {"YOUR SOCKET LINKED"}; Linux_Win_Init(); socketServer = socket(AF_INET, SOCK_STREAM, 0); memset(&serveDdr,0,sizeof(serveDdr)); serveDdr.sin_family = AF_INET; serveDdr.sin_addr.s_addr = htonl(INADDR_ANY); serveDdr.sin_port = htons(SERVER_PORT); bind(socketServer, (struct sockaddr *)&serveDdr, sizeof(serveDdr)); listen(socketServer, MAX_CLIENT); while (!g_ServeExit) { socketAddLen = sizeof(clildDdr); socketChild = accept(socketServer,(struct sockaddr *)&clildDdr, &socketAddLen); send(socketChild, buf, SOSKET_BUFSIZE,Linux_Win_SendRecvLastArg); Sleep(1); Linux_Win_CloseSocket(socketChild); } Linux_Win_Exit(); return 1; }
(3) 客户端代码 client.c
#ifdef WIN32 #include <windows.h> #include <winioctl.h> #include <tchar.h> #define UPDATE_TIME 1000*3 static LPWSTR serviceName = _T("SERVER"); static SERVICE_STATUS hServStatus; static SERVICE_STATUS_HANDLE hSStat; #else #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #endif #include <stdio.h> #include "server.h" #ifdef WIN32 //win32 #pragma comment(lib,"wsock32") //dll库调用准备 #endif void Linux_Win_Init() //win 32 socket初始化代码 { #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2 ); WSAStartup( wVersionRequested, &wsaData ); #endif } void Linux_Win_Exit() //win32 socket结束代码 { #ifdef WIN32 WSACleanup( ); #endif } #define SERVER_PORT 8111 #define SOSKET_BUFSIZE 1024 #define SERVER_IP "192.168.3.36" int main() { Linux_Win_SOCKET socketChild; struct sockaddr_in serveDdr; char buf[SOSKET_BUFSIZE] = {0}; Linux_Win_Init(); socketChild = socket(AF_INET, SOCK_STREAM, 0); memset(&serveDdr,0,sizeof(serveDdr)); serveDdr.sin_family = AF_INET; serveDdr.sin_addr.s_addr = inet_addr(SERVER_IP); // inet_pton(AF_INET, SERVER_IP, &serveDdr.sin_addr); serveDdr.sin_port = htons(SERVER_PORT); if(Linux_Win_SocketError != connect(socketChild, (struct sockaddr *)&serveDdr, sizeof(serveDdr)) ) { recv(socketChild,buf,SOSKET_BUFSIZE,Linux_Win_SendRecvLastArg); printf("receive string: %s ",buf); } Linux_Win_CloseSocket(socketChild); Linux_Win_Exit(); return 0; }