我写了一个小网络服务器,它只需要向浏览器发送一个 html 页面或错误页面。只是为了练习我的新套接字知识。
在这个程序中,我试图使用 select 方法来处理超过 1 个请求。
该程序接受了我的连接,但没有任何反应...... firefox 仍在继续加载文件,但该文件从未出现过,并且该程序没有做任何事情(虽然它没有崩溃。)。
这是我的代码:
#include <stdio.h>
#include <winsock2.h>
#include <winsock.h>
#include <Ws2tcpip.h>
#include <time.h>
#pragma comment(lib, "ws2_32.lib" )
#define BUFFSIZE 512
#define PORT "9001"
#define MAXCONNECTIONS 10
char * getPath(char * input, int var, char result[]);
void sendHeader(char * ext, char *path, int socketDescr, int code);
void sendBody(char * ext, char *path, int socketDescr, int code);
int main()
{
WSADATA wsaData;
struct timeval tv; // timeinterval for request (should arrive in less than 2seconds)
fd_set master; // keeps track of all open file descriptors + listener
fd_set read_fds; // list of file descriptors to read from
int fdmax; // max file descriptor number
int listener; // file descriptor on socket
int newfd; // new client file descriptor
struct sockaddr_storage clientaddr; // client address
socklen_t addrlen; // length of address
char clientIP[INET_ADDRSTRLEN]; // client ip-address (ipv4)
char buffer[BUFFSIZE]; // buffer for request
char request[BUFFSIZE]; // buffer for request
int recvbytes; // amount of bytes received
int yes = 1; // reuse address
int i,rv;
struct addrinfo serverinfo, *socketlist, *sock;
char result[BUFFSIZE];
char * path;
char * extension;
if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
{
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
// Set up time interval
tv.tv_sec = 5;
tv.tv_usec = 0;
// Clean up file descriptor sets
FD_ZERO(&master);
FD_ZERO(&read_fds);
// Get a socket and bind for listening
memset(&serverinfo, 0, sizeof(serverinfo));
serverinfo.ai_family = AF_INET;
serverinfo.ai_socktype = SOCK_STREAM; // TCP
serverinfo.ai_flags = AI_PASSIVE; // we search a socket on our side (server side) for listening
if((rv = getaddrinfo(NULL,PORT,&serverinfo,&socketlist)) != 0)
{
fprintf(stderr,"Server: %s\n",gai_strerror(rv));
exit(1);
}
// loop trough sockets
for(sock = socketlist; sock != NULL; sock = sock->ai_next)
{
listener = socket(sock->ai_family, sock->ai_socktype, sock->ai_protocol);
if(listener < 0)
{
continue; // not correct socket
}
setsockopt(listener,SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(int));
if(bind(listener, sock->ai_addr, sock->ai_addrlen) < 0)
{
closesocket(listener);
continue; // could not bind to socket
}
break;
}
// if could not get socket
if(sock == NULL)
{
fprintf(stderr,"Server: %s\n","Could not bind to socket");
exit(2);
}
// free up list, we have the socket
freeaddrinfo(socketlist);
// listen on socket
if(listen(listener,MAXCONNECTIONS) < 0)
{
perror("Server: listen");
exit(3);
}
// add listener to master set
FD_SET(listener,&master);
fdmax = listener;
fprintf(stdout,"Server: %s\n","Waiting for connections...");
for(;;)
{
read_fds = master;
if(select(fdmax+1,&read_fds,NULL,NULL,&tv) < 0)
{
perror("Server: select");
exit(4);
}
// run through existing connections to see if request has arrived
for(i = 0; i <= fdmax; i++)
{
if(FD_ISSET(i, &read_fds))
{
if(i == listener)
{
// we have a new connection
addrlen = sizeof clientaddr;
if((newfd = accept(listener,(struct sockaddr*)&clientaddr,&addrlen)) < 0)
{
perror("Server: accept");
exit(5);
}
else
{
FD_SET(newfd,&master);
if(newfd > fdmax)
{
fdmax = newfd;
}
fprintf(stdout, "Server: New connection from %s on socket %d\n",inet_ntop(clientaddr.ss_family, &(((struct sockaddr_in*)((struct sockaddr*)&clientaddr))->sin_addr), clientIP, sizeof(clientIP)),newfd);
}
}
else
{
// handle data from request
if((recvbytes = recv(i,buffer,BUFFSIZE-1,0)) <= 0)
{
if(recvbytes == 0) //connection closed
{
fprintf(stdout,"Server: socket %d goodbye\n",i);
}
else //request error [BAD REQUEST]
{
perror("Server: recv");
}
closesocket(i);
FD_CLR(i,&master);
}
else
{
recvbytes = recv(i, buffer,BUFFSIZE-1 , 0);
if(recvbytes > 0)
{
buffer[recvbytes]='\0';
strcat(request,buffer);
}
fprintf(stdout,"Server: request received:\n");
printf("%s", request);
//Get path
path = getPath(request,0, result);
if(strcmp(path,"error") != 0)
{
extension = getPath(request,1,result);
if(strcmp(extension,"error") != 0)
{
// send file 200
sendBody(extension,path,i,200);
}
}
else
{
// send code 400
sendBody("html","400.html",i,400);
}
closesocket(i);
FD_CLR(i,&master);
}
}
}
}
}
return 0;
}
// Gives path, extension of file or error
char * getPath(char * input, int var, char result [])
{
char * pch;
char str[BUFFSIZE];
strcpy(str,input);
pch = strtok(str,"\r\n");
pch = strtok(pch," ");
if(strcmp(pch,"GET") != 0)
{
strcpy(result,"error");
return result;
}
pch = strtok(NULL," ");
if(var == 0)
{
strcpy(result,pch);
return result;
}
pch = strtok(pch,".");
pch = strtok(NULL,".");
if(var == 1)
{
strcpy(result,pch);
return result;
}
return 0;
}
//Send header
void sendHeader(char * ext, char *path, int socketDescr, int code)
{
FILE * fp;
int fileSize = 0;
char fileSizeChar[32];
char * header;
char * status;
char * contenType;
char * contentLength;
char * msg;
if((fp = fopen(path, "r")) == NULL)
{
printf("Error opening file %s\n",path);
return;
}
//Get filesize
fseek(fp, 0L, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0L, SEEK_SET);
fclose(fp);
//Create header response message
header = "HTTP/1.0 ";
if(code == 200)
strcpy(status,"200");
else if(code == 400)
strcpy(status,"400");
else if(code == 404)
strcpy(status,"404");
if(strcmp(ext,"html") == 0)
strcpy(contenType," text/html\n");
//create and send header
strcat(msg,header);
strcat(msg,status);
strcat(msg,contenType);
strcat(msg,contentLength);
strcat(msg,fileSizeChar);
send(socketDescr, msg, strlen(msg), 0);
}
//Sending data like, pictures, zip, html pages... or an error html page
void sendBody(char * ext, char *path, int socketDescr, int code)
{
FILE * fp;
int fileSize = 0;
int sendBytes = 0;
int resultRead;
int resultSend;
char buffer[1000];
if((fp = fopen(path, "r")) == NULL)
{
printf("Can't open file %s\n",path);
if(code == 400)
{
printf("Error page 400 doesn't exist.\n");
return;
}
if((fp = fopen("404.html","r")) == NULL)
{
printf("Error page 404 doesn't exist.\n");
return;
}
strcpy(ext,"html");
strcpy(path,"404.html");
code = 404;
}
sendHeader(ext,path,socketDescr,code);
fseek(fp, 0L, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0L, SEEK_SET);
while(sendBytes < fileSize)
{
fseek(fp,sendBytes,SEEK_SET);
resultRead = fread(buffer,sizeof buffer[0],1000,fp);
resultSend = send(socketDescr,buffer,resultRead,NULL);
sendBytes +=resultSend;
}
fclose(fp);
}
显示的唯一行是“ Server: New connection from %s on socket ”。
有人能帮助我吗?
亲切的问候,