我正在使用C语言编写一个可移植的应用程序(windows -linux)客户端-服务器。
此应用程序必须能够使用一组固定的线程或一组固定的进程来处理客户端请求。
我正在使用curl作为客户端。
我很容易用pthread解决了线程问题。就流程而言,问题要复杂一些。
当主服务器接收到客户端的请求时,它将收到一个身份验证标头,其中包含用base64编码的用户ID和密码。
使用线程,每个线程都可以读取该标头,而使用进程则不会发生这种情况。由主服务器创建的用于处理recv上的请求块的进程,即使在复制之前的套接字上已经准备好读取此认证标头。这是由于复制期间发生了什么吗?
最初是为了了解一切工作原理,我写了有关其中代码的信息:
1主服务器接受客户端请求
if ((clientSocket = accept(MySocket, (struct sockaddr *)&cad,&clientLen)) < 0) {
ErrorHandler("accept() failed.\n");
// CHIUSURA DELLA CONNESSIONE
closesocket(MySocket);
ClearWinSock();
return 0;
}
2主服务器创建一个命名管道
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_UNLIMITED_INSTANCES,
512,
512,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
3主服务器创建一个必须处理该请求的进程
STARTUPINFO info;
GetStartupInfo(&info);
WSAPROTOCOL_INFO protInfo;
PROCESS_INFORMATION processInfo;
if(CreateProcess("connectionHandler.exe",NULL, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
printf("ok");
}
else
{
printf("server:The process could not be started...\n");
}
4主服务器复制套接字客户端,并等待新创建的进程连接到管道以接收重复的套接字,并使用命名管道将重复的客户端套接字传递给创建的进程
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
printf("process connected\n");
if ( WriteFile(hPipe, &clientSocket, sizeof(clientSocket), &dwBytes, NULL) == 0 ) {
return -1;
}
if ( WriteFile(hPipe, &protInfo, sizeof(protInfo), &dwBytes, NULL) == 0 ) {
return -1;
}
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
buffer[dwRead] = '\0';
printf("from client: %s", buffer);
}
}
printf("data passed to process\n");
fflush(stdout);
DisconnectNamedPipe(hPipe);
5创建的进程使用此套接字读取数据。
hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
WriteFile(hPipe,
"Hello Pipe\n",
12, // = length of string + terminating '\0' !!!
&dwWritten,
NULL);
dwMode = PIPE_READMODE_BYTE;
SetNamedPipeHandleState(
hPipe,
&dwMode, // new mode
NULL,
NULL);
ReadFile(hPipe, &sock_client, sizeof(sock_client), &dwBytes, NULL);
printf("client: sock client = %i\n",sock_client);
fflush(stdout);
/* I read the protocol information structure sent me by the parent process */
ReadFile(hPipe, &protInfo, sizeof(protInfo), &dwBytes, NULL);
printf("protocol read\n");
fflush(stdout);
sock_client = WSASocket(AF_INET, SOCK_STREAM, 0, &protInfo, 0, WSA_FLAG_OVERLAPPED);
printf("calling connection_handler...\n"); //function that cal recv and read the header
fflush(stdout);
connection_handler((void*)sock_client);
7:connection_handler((void *)sock_client):
此函数获取指向重复套接字的指针,并调用recv接收标头,然后通过推断base64字符串并对其进行解码来对标头进行处理。
它可以完美地与线程配合使用,但是在recv上阻塞,就好像客户端发送的标头在接受与主服务器的连接时一样,在套接字的复制和传递后丢失了。
功能代码:
printf("start connection handler\n");
fflush(stdout);
//Get the socket descriptor
int sock = *(int*)socket_desc;
char server_reply[2000];
int recv_size;
printf("preparing to receive client data\n");
fflush(stdout);
if((recv_size = recv(sock , server_reply , 2000 , 0)) == SOCK_ERR)
{
printf("recv failed");
fflush(stdout);
}
else
{
printf("Reply received\n");
fflush(stdout);
}
...
有什么理论可以逃避我吗? ps:请不要评论代码的样式,它只是一种了解进程与套接字通道之间的通信方式的测试。