示例项目

Linux网络编程基础

Linux提供了套接字api来实现网络通信。不幸的是,教科书没有提供任何关于这个主题的内容,所以这里提供了一个在线教程的链接,该教程涵盖了Linux套接字编程的基础知识。

MiniWeb服务器

作为网络程序的第一个例子,我们将构建一个非常小的web服务器。这个web服务器将能够从本地文件夹中的一组文件中提供静态内容。

要编译和运行服务器,首先单击这些注释顶部的按钮,下载miniweb服务器的项目文件夹。展开存档文件,然后在Visual Studio Code中打开MiniWeb文件夹。打开一个终端,运行这些命令:

miniweb. /miniweb .c

要确认web服务器工作正常,请在计算机上打开浏览器并粘贴以下URL:

http://localhost:8888/index.html

这将为您提供一个确认页面,以确认服务器已启动并运行。

要停止服务器,请在终端窗格中按control-c组合键。

更多关于web服务器的知识

当浏览器从web服务器请求某些内容时,它将构造一个HTTP请求并将其发送到服务器。请求的结构是一个头列表和一个可选的主体。请求中的第一行采用这种形式

<动词> <URL> <HTTP版本>

最简单的HTTP请求类型是GET请求,它使用GET作为它的 。我们简单的web服务器将只响应GET请求。在简单GET请求的情况下, 将是文件的路径。我们的服务器将打开请求的文件并将其发送回客户端。

要发回构造正确的响应,服务器必须使用响应标头列表进行响应,后面跟着请求的内容。响应头的最小集应该是这样的:

HTTP/1.1 200 OK Content-Type: text/html Content-Length: <Length> . html

这里 是内容的长度,以字节为单位。在响应标头之后,我们需要提供一个空行,后面跟着响应内容。

如果在服务器上找不到请求的文件,则响应的第一行更改为

HTTP/1.1 404未找到

并且响应的主体更改为服务器的未找到页面。

设置套接字

web服务器程序的main()函数执行开始侦听来自客户机的连接所需的基本步骤。

int main(){//创建套接字int server_socket = socket(AF_INET, SOCK_STREAM, 0);如果server_socket == -1) {printf(“无法创建socket.\n”);返回1;} //准备sockaddr_in结构struct sockaddr_in server;服务器。sin_family = AF_INET;server.sin_addr。s_addr = INADDR_ANY;服务器。Sin_port = htons(8888);//绑定到我们想要使用的端口if(Bind (server_socket,(struct sockaddr *)&server, sizeof(server)) < 0) {printf(“绑定失败\n”);返回1;} printf("Bind done\n");//将socket标记为被动socket listen(server_socket, 3);//接受传入连接printf("Waiting for incoming connections…\n");当(1){struct sockaddr_in客户端;Int new_socket, c = sizeof(struct sockaddr_in);New_socket = accept(server_socket, (struct sockaddr *) &client, (socklen_t*)&c);if(new_socket != -1) serverrequest (new_socket);}返回0;}

我们需要使用四个函数来建立到客户机的连接。

  1. 套接字()创建一个新的服务器套接字并返回一个可用于引用该套接字的文件描述符。
  2. bind ()将服务器套接字连接到服务器将侦听的端口。该服务器将监听端口8888上的连接。
  3. 听()将套接字更改为被动模式,以准备接收来自客户端的传入连接。
  4. accept ()将服务器套接字置于等待状态,以等待客户端连接到服务器。当客户端连接时accept ()将返回一个新的套接字的文件描述符,我们可以使用它与客户端通信。

处理请求

serverrequest()函数处理来自客户端的单个请求。

void serverrequest (int fd){//读取请求字符缓冲区[1024];int bytesRead = read(fd,buffer,1023);buffer[bytesRead] = '\0';char[16]方法;char url [128];sscanf(缓冲区,“% s % s”方法,url);char文件名[128];strcpy(文件名,“www”);strcat(文件名、url);int file = open(fileName,O_RDONLY);if(filed == -1){//用户请求了一个我们没有的文件。//返回404错误响应。int f404 = open("404Response.txt",O_RDONLY);int readSize = read(f404,buffer,1023);关闭(f404);写(fd,缓冲区,readSize);} else {const char* responseStatus = "HTTP/1.1 200 OK\n";const char* responseOther = “连接:关闭\nContent-Type: text/html\n”;//获取文件char len[64]的大小;Struct stat;fstat(提交、办法);sprintf(len,"Content-Length: %d\n\n",(int) st.st_size);//发送报头write(fd,responseStatus,strlen(responseStatus));写(fd, responseOther strlen (responseOther));写(fd, len strlen (len));//发送文件while(bytesRead = read(file,buffer,1023)) {write(fd,buffer,bytesRead);}关闭(提交);}关闭(fd);}

我们需要读取的请求的唯一一行是第一行。这一行包含所请求文件的方法和URL。

当请求进入时,我们尝试打开请求的文件。如果我们不能打开它,我们返回一个HTTP 404 ‘Not Found’错误响应。由于此响应总是相同的,因此我们可以提前准备一个文本文件来存储响应,然后将该文件的内容发送给客户机。以下是我们将发送的响应:

HTTP/1.1 404未找到连接:关闭内容类型:text/html内容长度:124 <!DOCTYPE html> <head> <title>File not found</title> </head> <body> <p>请求的文件未找到。< / p > < /身体>

如果我们能够打开请求的文件,我们将构造适当的响应头,并将它们发送回客户机,然后发送文件的内容。发送文件内容的逻辑反复地从文件中读取数据块,并将它们写到客户端,直到文件中的赢博体育数据都发送完毕。当我们从文件中读取赢博体育可能的内容时,read()将返回字节计数为0,这将导致我们退出读/写循环。

在响应客户端的请求后,我们继续并关闭与客户端的套接字连接。