不少時候咱們要開發 服務器程序應用linux 和windows平臺,不少時候得兩套開發代碼。我這裏選擇跨平臺開發,已經在windows7 和 ubuntu 12.04 下,經html
過測試,windows 稱服務,linux稱守護進程, 本質都是同樣。linux
若是對服務守護進程不是很瞭解,能夠參考【linux c 速學筆記】/【守護進程與socket編程】一章 ttp://www.cnblogs.com/wolfrickwang/p/3192949.html編程
關於命名規範問題,因爲本程序在windows 平臺下面編寫,linux 下面測試 因此命名規範偏向windows 平臺開發慣用命名規範。ubuntu
現將代碼張貼以下: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.csocket
/******************************** @跨平臺開發服務測試 ********************************/ #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\n",buf); } Linux_Win_CloseSocket(socketChild); Linux_Win_Exit(); return 0; }