网络编程模式中,有一种是多进程模式,主进程侦听,收到连接后,启动子进程处理请求,每个连接一个子进程。
在linux中通过fork很容易实现,因为fork时子进程继承父进程的文件描述符,套接字也是一种文件描述符。
在windows句柄也能够继承,但是必须通过外部方法告诉子进程句柄值,可以通过命令行参数或者环境变量的方式传递。
怎么获取套接字的句柄呢?其实套接字本身就是一个句柄,只是平常使用recv、send来操作套接字,没觉得它是一个句柄。
需要注意的是,在win 9x中,套接字句柄默认是不继承的,需要使用复制句柄(DuplicateHandle)函数复制一个可继承的句柄。
主进程代码片段:
// This is a Winsock server that is listening on a port. // When a client connects, the server spawns a child process and // passes the socket handle to the child. // The child can use this socket handle to interact with the // client and the parent is free to go back to waiting for // other clients to connect. OrigSock=accept(listen_socket,(struct sockaddr *)&from,&fromlen); if (OrigSock == INVALID_SOCKET) { fprintf(stderr,"accept failed %d\n",GetLastError()); return -1; } { STARTUPINFO si; PROCESS_INFORMATION pi; char argbuf[256]; memset(&si,0,sizeof(si)); // // Duplicate the socket OrigSock to create an inheritable copy. // if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)OrigSock, GetCurrentProcess(), (HANDLE*)&DuplicateSock, 0, TRUE, // Inheritable DUPLICATE_SAME_ACCESS)) { fprintf(stderr,"dup error %d\n",GetLastError()); return -1; } // // Spawn the child process. // The first command line argument (argv[1]) is the socket handle. // wsprintf(argbuf,"child.exe %d",DuplicateSock); if (!CreateProcess(NULL,argbuf,NULL,NULL, TRUE, // inherit handles 0,NULL,NULL,&si,&pi) ){ fprintf(stderr,"createprocess failed %d\n",GetLastError()); return -1; } // // On Windows 95, the parent needs to wait until the child // is done with the duplicated handle before closing it. // WaitForSingleObject(pi.hProcess, INFINITE); } // // The duplicated socket handle must be closed by the owner // process--the parent. Otherwise, socket handle leakage // occurs. On the other hand, closing the handle prematurely // would make the duplicated handle invalid in the child. In this // sample, we use WaitForSingleObject(pi.hProcess, INFINITE) to // wait for the child. // closesocket(OrigSock); closesocket(DuplicateSock);
子进程代码片段:
main(int argc, char *argv[]){ SOCKET Sock; /* WSAStartup etc. */ if (2 == argc){ Sock = atoi(argv[1]); // use Sock } }