简单的网络服务器将无法工作
Simple webserver won't work
我正在尝试用 C 编写一个网络服务器。我知道我可以为此使用许多不同的库,但我希望它 运行 仅与 winsock 一起使用。服务器和客户端可以来回发送数据,但无法加载网页。每次我收到 'server unreachable' 消息,但在服务器上我收到正文已发送的消息。我做错了什么?
编辑 我正在使用 chrome 和 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);
编辑的值 return,您将看到 SOCKET_ERROR
。调用 WSAGetLastError()
将 return
Code 0x2745 = An established connection was aborted by the software in your host machine.
你读socket的方式真丑!使用 ioctlsocket()
和 FIONREAD
来获取要读取的字符数:
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;
}
要使用它修复您的来源:
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();
}
我正在尝试用 C 编写一个网络服务器。我知道我可以为此使用许多不同的库,但我希望它 运行 仅与 winsock 一起使用。服务器和客户端可以来回发送数据,但无法加载网页。每次我收到 'server unreachable' 消息,但在服务器上我收到正文已发送的消息。我做错了什么?
编辑 我正在使用 chrome 和 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);
编辑的值 return,您将看到 SOCKET_ERROR
。调用 WSAGetLastError()
将 return
Code 0x2745 = An established connection was aborted by the software in your host machine.
你读socket的方式真丑!使用 ioctlsocket()
和 FIONREAD
来获取要读取的字符数:
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;
}
要使用它修复您的来源:
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();
}