我正在尝试用C编写一个网络服务器。我知道我可以使用许多不同的库,但我希望它只能用winsock运行。服务器和客户端可以来回发送数据,但加载网页是不可能的。每次我收到“服务器无法访问”消息,但在服务器上我收到正在发送正文的消息。我做错了什么?
编辑我正在使用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();
}
答案 0 :(得分:0)
此功能:
void flush(SOCKET s){
while(recv(s, NULL, 1, 0)>0){
}
}
在客户端(浏览器)重置连接之前,不会读取缓冲区中的所有内容。
如果您检查send(csock, response, strlen(response), 0);
返回的值,则会看到SOCKET_ERROR
。致电WSAGetLastError()
将返回
代码0x2745 =已建立的连接已被主机中的软件中止。
你用来读取套接字的方式真是太丑了!将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();
}