【发布时间】:2015-12-09 18:26:55
【问题描述】:
我通过套接字在 c 中创建服务器。客户端向服务器发送请求。服务器对其进行解析并发送回数据(html、png、jpg 或 bash 脚本输出)。我对此有一些疑问。
当我读取 html 文件并将其发送给客户端时。如果文件很大,则不发送数据并且浏览器重置连接The connection was reset我怎样才能等到所有数据都发送完毕?在这个循环中。
while ((ret = read(html, buff, 1023)) > 0)
{
write(client_socketfd, buff, ret);
}
是否可以像 html 一样发送图像(png 或 jpg),只更改 html 标头中的内容类型?
如果在 html 文件中有一个带有 src="another.html" 的标签,点击后客户端发送 GET 请求,它是如何工作的?
如果html文件中有img标签,它是如何工作的?
最后一个问题是什么是关闭无限循环服务器的最佳方式。在 linux 中,如果我用CTRL C 关闭它,socket 就不会关闭。
如果有其他问题,我将不胜感激您的建议。
int main(int argc, char *argv[])
{
int result;
int socket_desc, client_socketfd, c, read_size, buffer = 0;
struct sockaddr_in server, client;
char sprava[256];
int arg;
int port = 0;
char *homeDir = NULL;
//get command line arguments -p port -d home dir
while ((arg = getopt(argc, argv, "p:d:")) != -1) {
switch (arg) {
case 'p':
port = atoi(optarg);
break;
case 'd':
homeDir = optarg;
break;
default:
fprintf(stderr, "Please speicify -p port and -d home directiory\n");
exit(1);
}
}
if (port < 1500 || homeDir == NULL) {
fprintf(stderr, "BAD arguments use: -p port(greather then 1500) -d home dir\n");
exit(1);
}
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
return 1;
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
//Bind
if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0)
{
fprintf(stderr, "bind failed\n");
exit(1);
}
printf("bind done\n");
//Listen max 3
listen(socket_desc, 3);
//Accept and incoming connection
int loop = 1;
while (loop) {
printf("Waiting for incoming connections...\n");
c = sizeof(struct sockaddr_in);
loop = 0; //only for testing, if everything run ok loop will be infinity
client_socketfd = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_socketfd < 0) {
fprintf(stderr, "Accept failed\n");
exit(1);
}
//In child proc we are sending data
if (fork() == 0) {
close(socket_desc);//we dont need desc in child
bzero(sprava, 256);//all on '\0'
result = read(client_socketfd, sprava, 255);
printf("Server read: %s\n", sprava);
char* path;
int kod = parser(sprava, &path);//in path is path to file
if (kod == ERROR_FILE_TYPE)
{
printf("BAD request!!!!\n");
shutdown(client_socketfd, SHUT_RDWR);
close(client_socketfd);
}
if (kod == HTML || kod == BASH || kod == JPG || kod == PNG)
{
if (kod == BASH)
{
FILE *pipe;
char *cmd = path;
strcat(cmd, " 2>&1");//error output send to pipe
printf("New command is=%s\n", cmd + 1);//we dont need first /
//open pipe without first /
pipe = popen(cmd + 1, "r");
if (pipe != NULL) {
char text[1035];
while (fgets(text, sizeof(text) - 1, pipe) != NULL) {
printf("output=%s", path);
write(client_socketfd, text, strlen(text));
}
}
pclose(pipe);
}
else if (kod == HTML)
{
int html;
long len;
char buff[1024] = { 0 };
int ret;
printf("Try to open file=%s\n", path + 1);
html = open(path + 1, O_RDONLY);
if (html == -1) {
fprintf(stderr, "Error opening file\n");
}
len = (long)lseek(html, (off_t)0, SEEK_END);//len of file
lseek(html, (off_t)0, SEEK_SET);
sprintf(buff, "HTTP/1.1 200 OK\nServer: nweb/%d.0\nContent-Length: %ld\nConnection: close\nContent-Type: %s\n\n", 20, len, "text/html");
//send html header to client
printf("Length of file=%d\n", len);
write(client_socketfd, buff, strlen(buff));
printf("Header was send\n");
while ((ret = read(html, buff, 1023)) > 0)
{
printf("number of bytes read=%d\n", ret);
//write data to client,it will make connection reset
write(client_socketfd, buff, ret);
}
}
free(path);
}
shutdown(client_socketfd, SHUT_RDWR);
close(client_socketfd);
exit(0);
}
//in parent close client
else {
close(client_socketfd);
wait(&wt);//this wait is only for testing
}
}
close(socket_desc);
return 0;
}
【问题讨论】:
-
http RFC(规范)在这里:w3.org/Protocols(7230 到 7235)
-
另外,您想针对您的每一个问题提出一个 SO 问题。
-
另外^2 请注意,来自套接字的
read()ing 不一定返回请求的字节数,但很少。读取次数不需要与写入次数相匹配。仔细阅读文档。 -
最后也是为了帮自己一个忙总是测试函数调用的结果,至少在它们返回与以下代码相关的任何值的情况下。
-
一个细节:不要做
int c; ... ... (socklen_t*) &c);,而只是socklen_t c; ... ... &c);。想象一下如果int的大小与socklen_t的大小不同会发生什么。