网络编程模式中,有一种是多进程模式,主进程侦听,收到连接后,启动子进程处理请求,每个连接一个子进程。
在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
}
}