在TCP/IP套接字(Web服务器)上发送文件
在TCP/IP套接字(Web服务器)上发送文件
我在写一个Web服务器的框架,但是我弄不清楚为什么我的文件没有通过套接字发送,我已经连接到它了,但是它没有调用send()
发送我的文件...我漏掉了什么吗?
//代码 (server.c)
#include<netinet/in.h> #include #include #include<sys/socket.h> #include<sys/stat.h> #include<sys/types.h> #include int main(void) { int create_socket, new_socket; socklen_t addrlen; int bufsize = 1024; char *buffer = malloc(bufsize); struct sockaddr_in address; if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0){ printf("The socket was created\n"); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(80); if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0){ printf("Binding Socket\n"); } long fsize; FILE *fp = fopen("index.html", "r"); fseek(fp, 0, SEEK_END); fsize = ftell(fp); rewind(fp); char *msg = malloc(fsize + 1); fread(msg, sizeof(msg), 1, fp); while (1) { if (listen(create_socket, 10) < 0) { perror("server: listen"); exit(1); } if ((new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen)) < 0) { perror("server: accept"); exit(1); } if (new_socket > 0){ printf("The Client is connected...\n"); } recv(new_socket, buffer, bufsize, 0); printf("%s\n", buffer); write(new_socket, "HTTP/1.1 200 OK\n", 16); write(new_socket, "Content-length: 46\n", 19); write(new_socket, "Content-Type: text/html\n\n", 25); /* write(new_socket, "
Hello world
",46); */ if((send(new_socket, msg, fsize+1, 0)) > 0){ printf("success"); } else{ printf("failed"); } close(new_socket); } close(create_socket); return 0; }
//文件 (index.html) *同一个目录
Hello World
admin 更改状态以发布 2023年5月24日
fsize = ftell(fp); rewind(fp); char *filebuff = malloc(fsize + 1);
为什么要使用fsize+1
?你不需要+1
。
fread(filebuff, sizeof(filebuff), 1, fp);
未检查返回值。第二个参数应该是fsize
。目前你只传递了指针的sizeof
。
//create/bind socket if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) > 0) { printf("The socket was created\n"); }
如果套接字创建失败了,你必须(a)按照下面的描述打印一个适当的错误消息,并(b)不能像错误没有发生一样继续执行。
if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == 0) { printf("Binding Socket\n");
}
一样。
//listen, create new_sock, write headers, send file while (1){ if (listen(create_socket, 10) < 0) { perror("server: listen"); exit(1); }
listen()
调用应该在循环前面而不是循环内部。这是你真正处理失败情况的第一次。
new_sock = accept(sock, (struct sockaddr *) &address, &addrlen); recv(new_socket, buffer, bufsize, 0); printf("%s\n", buffer);
无效。未检查返回代码。如果recv()
返回一个正整数,缓冲区才有效,并且只有这么多字节是有效的。应该是这样的:
int count = recv(new_socket, buffer, bufsize, 0); printf("%.*s\n", count, buffer);
然后我们开始处理HTTP:
write(new_sock, "HTTP/1.1 200 OK\n", 16); write(new_sock, "Content-length: 46\n", 19); write(new_sock, "Content-Type: text/html\n\n", 25);
HTTP中的行终止符是从Telnet继承来的,指定为\r\n
而不是\n
。
if(send(new_sock, filebuff, fsize+1, 0) > 0){ printf("success"); } else{ printf("failed"); }
不足。如果你从任何系统调用中得到错误,你必须调用perror()
,或者在错误消息中使用errno
或strerror()
。"失败"传达不了有用的信息,而调试成为了一个单纯的猜谜游戏。不要编写这样的代码。对于上面所有其他未检查的返回值,你应该使用perror()
或你决定使用的任何其他方法。
但是有一个更大的问题。你假设文件适合内存。没有必要这样假设。只需使用8k缓冲区复制文件,如下所示:
int count; while ((count = read(in, buffer, sizeof buffer)) > 0) { send(out, buffer, count, 0); } if (count < 0) { perror("send failed"); }
我会避免使用stdio
,因为它有太多的问题,比如设计不良的fread()
和 fwrite()
函数API。
这段代码有很多不同的原因导致完全崩溃。建议改成以下代码:
#include#include #include #include #include #include #include bool writeDataToClient(int sckt, const void *data, int datalen) { const char *pdata = (const char*) data; while (datalen > 0){ int numSent = send(sckt, pdata, datalen, 0); if (numSent <= 0){ if (numSent == 0){ printf("The client was not written to: disconnected\n"); } else { perror("The client was not written to"); } return false; } pdata += numSent; datalen -= numSent; } return true; } bool writeStrToClient(int sckt, const char *str) { return writeDataToClient(sckt, str, strlen(str)); } int main(void){ int create_socket, new_socket; char *buffer; int bufsize = 1024; struct sockaddr_in address; socklen_t addrlen; buffer = (char*) malloc(bufsize); if (!buffer){ printf("The receive buffer was not allocated\n"); exit(1); } create_socket = socket(AF_INET, SOCK_STREAM, 0); if (create_socket == -1){ perror("The socket was not created"); exit(1); } printf("The socket was created\n"); memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(80); if (bind(create_socket, (struct sockaddr *) &address, sizeof(address)) == -1){ perror("The socket was not bound"); exit(1); } printf("The socket is bound\n"); long fsize; FILE *fp = fopen("index.html", "rb"); if (!fp){ perror("The file was not opened"); exit(1); } printf("The file was opened\n"); if (fseek(fp, 0, SEEK_END) == -1){ perror("The file was not seeked"); exit(1); } fsize = ftell(fp); if (fsize == -1) { perror("The file size was not retrieved"); exit(1); } rewind(fp); char *msg = (char*) malloc(fsize); if (!msg){ perror("The file buffer was not allocated\n"); exit(1); } if (fread(msg, fsize, 1, fp) != 1){ perror("The file was not read\n"); exit(1); } fclose(fp); printf("The file size is %ld\n", fsize); if (listen(create_socket, 10) == -1){ perror("The socket was not opened for listening"); exit(1); } printf("The socket is listening\n"); while (1) { addrlen = sizeof(address); new_socket = accept(create_socket, (struct sockaddr *) &address, &addrlen); if (new_socket == -1) { perror("A client was not accepted"); exit(1); } printf("A client is connected from %s:%hu...\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); // I will leave it as an exercise for you to implement // a proper HTTP request parser here... int numRead = recv(new_socket, buffer, bufsize, 0); if (numRead < 1){ if (numRead == 0){ printf("The client was not read from: disconnected\n"); } else { perror("The client was not read from"); } close(new_socket); continue; } printf("%.*s\n", numRead, buffer); if (!writeStrToClient(new_socket, "HTTP/1.1 200 OK\r\n")){ close(new_socket); continue; } char clen[40]; sprintf(clen, "Content-length: %ld\r\n", fsize); if (!writeStrToClient(new_socket, clen)){ close(new_socket); continue; } if (!writeStrToClient(new_socket, "Content-Type: text/html\r\n")){ close(new_socket); continue; } if (!writeStrToClient(new_socket, "Connection: close\r\n\r\n") == -1){ close(new_socket); continue; } //if (!writeStrToClient(new_socket, " Hello world
")){ if (!writeDataToClient(new_socket, msg, fsize)){ close(new_socket); continue; } printf("The file was sent successfully\n"); close(new_socket); } close(create_socket); return 0; }