我正在尝试使用 fork() 编写一个小型 HTTP 服务器。当我通过 firefox 连接到它时,它不会显示页面,直到我终止服务器。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <signal.h>
#define LISTEN_MAX 5
#define CONT_MAX 10000
#define PORT 8081
#define MAX_FILE 2
#define S_SHORT 50
#define MAX_CONTENT 1000
#define MAX_HEADER 200
const size_t BUF_LEN = 1024; //was 128
const size_t REQUEST_LEN=1024;
char file_names[MAX_FILE][S_SHORT];
FILE *file_deskriptors[MAX_FILE];
int file_sizes[MAX_FILE];
char file_contents[MAX_FILE][MAX_CONTENT];
// Something unexpected happened. Report error and terminate.
void sysErr( char *msg, int exitCode ) {
fprintf( stderr, "%s\n\t%s\n", msg, strerror( errno ) );
exit( exitCode );
}
// get_line was borrowed from Tiny HTTPd under GPLv2
// https://sourceforge.net/projects/tinyhttpd/?source=typ_redirect
int get_line(int sock, char *buf, int size) {
int i = 0;
char c = '\0';
int n;
while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
/* DEBUG printf("%02X\n", c); */
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
/* DEBUG printf("%02X\n", c); */
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}
void copyHeaderToBuffer(char *tx_buff, int *status) {
switch(*status) {
case 200: strcpy(tx_buff,"HTTP/1.0 200 OK\r\nContentÂtype: text/html\r\n\r\n"); break;
}
return;
}
void answer(int *accfd, char *request ) {
int file_size, file_index, status, sent_bytes;
file_size, file_index, status = 0;
char method[S_SHORT], ressource[S_SHORT], proto[S_SHORT];
char tx_buff[MAX_CONTENT+MAX_HEADER];
//rehash query
splitRequest(request, method, ressource, proto);
//check for <GET>
checkMethod(method);
//search the file and get index
getFileIndexByName(ressource, &file_index);
file_size = file_sizes[file_index];
status = getFileStatus(&file_index);
createAnswerMessage(tx_buff, &status, &file_index);
//send the answer
if ( (sent_bytes= write( accfd, tx_buff, strlen(tx_buff))) == -1 ) {
sysErr( "[-] Client Fault: SEND", -4 );
}
return;
}
void createAnswerMessage(char *tx_buff, int *status, int *file_index) {
copyHeaderToBuffer(tx_buff, status);
strcat(tx_buff,file_contents[*file_index]);
strcat(tx_buff,"\r\n");
return;
}
int getFileStatus(int *file_index) {
return 200;
}
void splitRequest(char *request, char *method, char *ressource, char *proto) {
char *temp;
if ((temp = strtok(request, " ")) != NULL) {
strcpy(method, temp);
}
if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(ressource, temp);
}
if ((temp = strtok(NULL, " ")) != NULL) {
strcpy(proto, temp);
}
//remove leading "/" from ressource
cleanRessource(ressource);
return;
}
void cleanRessource(char *ressource) {
if (*ressource == '/') {
printf("\nstr_len_ressource: %i",strlen(ressource));
for ( int i=0; i < strlen(ressource); i++ ) {
ressource[i]=ressource[i+1];
}
}
return;
}
void checkMethod(char *method){
if (strcmp(method, "GET") ) {
printf("\n[-] Error: Method \"%s\" not known .",method);
exit(0);
}
printf("\nincheckMethod method = %s",method);
return;
}
void getFileIndexByName (char *ressource, int *file_index) {
for (int i=0; i<MAX_FILE; i++) {
if ( !strcmp(ressource, file_names[i]) ) {
*file_index = i;
return;
}
}
printf("\[-] Error: File \"%s\" not known.",ressource);
exit(0);
}
void filesInit () {
memset(file_names, '\0', sizeof(file_names));
memset(file_contents, '\0', sizeof(file_contents));
//define your files here:
strcpy(file_names[0],"index.htm");
for (int i=0; i<MAX_FILE; i++) {
//choose only existing files
if (file_names[i][0]!='\0') {
//open file
file_deskriptors[i] = fopen(file_names[i],"r");
//get file size
fseek(file_deskriptors[i], 0, SEEK_END);
file_sizes[i] = ftell(file_deskriptors[i]);
//read the file content to file_contents
fseek(file_deskriptors[i], 0, SEEK_SET);
fread(file_contents[i], 1, CONT_MAX, file_deskriptors[i]);
}
}
return;
}
void filesClose() {
return;
}
int main(int argc, char **argv)
{
//kill childs if recieving SIGCHLD
signal(SIGCHLD,SIG_IGN);
int connfd, accfd;
struct sockaddr_in server_addr, client_addr;
socklen_t sockaddr_len = sizeof(struct sockaddr_in);
//initial the available files on server
filesInit();
// create socket
if ( ( connfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0) {
sysErr( "Server Fault : SOCKET", -1 );
}
// Set params so that we receive IPv4 packets from anyone on the specified port
memset( &server_addr, 0, sockaddr_len );
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( PORT );
//bind socket to port
if ( bind( connfd, (struct sockaddr *) &server_addr, sockaddr_len ) < 0 ) {
sysErr( "\n[-] Server Fault : BIND", -2 );
}else{printf("[+] SERVER ONLINE");}
//let server listen for incoming connections
if ( listen( connfd, LISTEN_MAX) < 0 ) {
sysErr( "[-] Server Fault : LISTEN", -3 );
}
//main loop for accepting clients
while ( true ) {
pid_t pid;
//connecting specific client
if ( (accfd=accept( connfd, (struct sockaddr *) &client_addr, &sockaddr_len )) < 0 ) {
sysErr( "[-] Server Fault : ACCEPT", -4 );
}
//fork & answer
else {
printf("\n[+] CLIENT CONNECTED\n");
switch ( pid = fork() ) {
case -1: {
printf("\n[-] Error while fork()");
return EXIT_FAILURE;
}
case 0: {
int req_line_len=1; //length of request line
int first_line_on = 1; //set first line parameter
char req_line[S_SHORT]; //current read line
char first_line[S_SHORT]; //save first line
memset(req_line, 0, S_SHORT);
memset(first_line, 0, S_SHORT);
printf("\n[+] HTTP REQUEST on accfd: %i",accfd);
//reading line by line from socket
while((req_line_len > 0) && strcmp("\n", req_line)){
req_line_len = get_line( accfd, req_line, S_SHORT-1);
//get first line and save it
if (first_line_on) { first_line_on = 0; strcpy(first_line,req_line); }
if((req_line_len > 0) && strcmp("\n", req_line)) printf("%s",req_line);
}
//answering to client
answer(accfd, first_line);
//close connection
if (!close(accfd)) {printf("\n[+] CONNECTION CLOSED");}
exit(0);
break;
}
default: {
//main process
break;
}
}
}
}
//close listening socket
close( connfd );
//close server files
filesClose();
return 0;
}
child 被终止了,我得到了 CONNECTION CLOSED 的答案
我的代码中是否存在逻辑错误?
编辑:
我添加了完整的最少代码。 我在传输消息中添加的“\r\n”。 如果我添加
它工作正常close(accfd);
到 main(),但我认为这实际上不是问题(只是一个副作用解决方案)
index.htm 可以是:
<html><body><b>index</b><br>C is a interesting language!</body></html>
最佳答案
当你调用 fork() 时,父进程的文件描述符被复制到子进程中,这就是为什么你仍然可以访问子进程中的套接字的原因。只要您至少有一个文件描述符对套接字打开,网络堆栈就会使套接字保持事件状态。您关闭了子进程中的套接字,但它仍然在父进程中打开。
换句话说,在父级中添加对 close(accfd) 的调用应该可以解决您的问题。
关于c - 服务器 - 浏览器仅在服务器终止后显示站点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40687716/
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article
我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c