问题描述
我正在尝试用C语言编写一个网络服务器.我知道我可以为此使用许多不同的库,但是我希望它只能与winsock一起运行.服务器和客户端可以来回发送数据,但是无法加载网页.每次我收到服务器无法访问"消息,但在服务器上却收到消息,指出正文已发送.我在做什么错了?
I'm trying to write a webserver in C. I know I could use many different libraries for that, but I want it to run only with winsock. The server and a client can send data back and forth but loading the webpage is impossible. Every time I get a 'server unreachable' message, but on the server I get the message that the body was sent. What am I doing wrong?
edit 我正在使用Chrome和Microsoft Edge
edit I'm using chrome and microsoft edge
#include <stdio.h>
#include <conio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")
void error(const char* err){
printf("ERROR: %s\n", err);
exit(1);
}
char* readline(SOCKET s){
FILE * f = tmpfile();
char rec;
int i=0;
while(recv(s, &rec, 1, 0)>0){
i++;
if(rec!='\r' && rec!='\n')
fwrite(&rec, 1, 1, f);
if(rec=='\r' || rec=='\n')
break;
}
if(i==0){
fclose(f);
return NULL;
}
fseek(f, 0, SEEK_END);
long long size = ftell(f);
fseek(f, 0, SEEK_SET);
char * d = (char*) malloc(size);
memset (d,0,size);
fread(d, 1, size, f);
fclose(f);
return d;
}
void flush(SOCKET s){
while(recv(s, NULL, 1, 0)>0){
}
}
void main(){
// CREATE SERVER
WSADATA wsa;
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
error("WSAStartup");
SOCKET s;
if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
error("socket");
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(80);
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
error("bind");
// SERVER CREATED
while(1){
listen(s, 1);
int c = sizeof(struct sockaddr_in);
SOCKET csock;
struct sockaddr_in client;
if((csock = accept(s, (struct sockaddr*)&client, &c))==INVALID_SOCKET)
continue;
char *client_ip = inet_ntoa(client.sin_addr);
printf("Incomming connection: %s\n", client_ip);
char * head = readline(csock);
if(strncmp(head, "GET", 3)==0){
flush(csock);
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<html><head><title>test</title>"
"</head><body>Test123</body></html>";
send(csock, response, strlen(response), 0);
printf("%s\n", "HTML body sended");
}else if(strncmp(head, "HEAD", 4)==0){
flush(csock);
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n";
send(csock, response, strlen(response), 0);
printf("%s\n", "HTML head sended");
}
closesocket(csock);
}
closesocket(s);
WSACleanup();
}
推荐答案
此功能:
void flush(SOCKET s){
while(recv(s, NULL, 1, 0)>0){
}
}
不读取任何内容,直到客户端(浏览器)重置连接后才将所有内容放入缓冲区.如果检查send(csock, response, strlen(response), 0);
返回的值,则会看到SOCKET_ERROR
.呼叫WSAGetLastError()
将返回
reads nothing letting all in the buffer until the client (the browser) reset the connection.If you check the value returned by send(csock, response, strlen(response), 0);
you'll see a SOCKET_ERROR
. Calling WSAGetLastError()
will return
您用来读取套接字的方式确实很丑陋!将ioctlsocket()
与FIONREAD
结合使用以获得要读取的字符数:
The way you use to read socket is really ugly! Use ioctlsocket()
with FIONREAD
to obtain the number of chars to read:
char* readline(SOCKET s)
{
size_t MsgLen = 0;
char *Msg = NULL;
unsigned long Len;
int res;
while (0 == (res=ioctlsocket(s, FIONREAD, &Len)))
{
if (SOCKET_ERROR == Len)
{
if (Msg)
{
free(Msg);
Msg = NULL;
}
return NULL;
}
if (!Len && MsgLen)
break;
if (!Msg)
Msg = malloc(Len);
else
Msg = realloc(Msg, MsgLen + Len);
recv(s, Msg+MsgLen, Len, 0);
MsgLen += Len;
}
return Msg;
}
要使用它来修复您的来源:
To use it fix your source:
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<html><head><title>test</title>"
"</head><body>Test123</body></html>\r\n";
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n";
int main(int argc, char *argv[])
{
// CREATE SERVER
WSADATA wsa;
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
error("WSAStartup");
SOCKET s;
if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
error("socket");
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(80);
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
error("bind");
// SERVER CREATED
while(1){
listen(s, 1);
int c = sizeof(struct sockaddr_in);
SOCKET csock;
struct sockaddr_in client;
if((csock = accept(s, (struct sockaddr*)&client, &c))==INVALID_SOCKET)
continue;
char *client_ip = inet_ntoa(client.sin_addr);
printf("Incoming connection: %s\n", client_ip);
char * head = NULL;
do
{
head = readline(csock);
} while (!head);
if(strncmp(head, "GET", 3)==0)
{
if (SOCKET_ERROR == send(csock, response, strlen(response), 0))
{
WSAGetLastError();
}
printf("%s\n", "HTML body sended");
}
else
if(strncmp(head, "HEAD", 4)==0)
{
send(csock, response, strlen(response), 0);
printf("%s\n", "HTML head sended");
}
closesocket(csock);
}
closesocket(s);
WSACleanup();
}
这篇关于简单的网络服务器无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!