网络编程:基于C语言的简易代理服务器实现(proxylab) 您所在的位置:网站首页 c语言服务器开发 网络编程:基于C语言的简易代理服务器实现(proxylab)

网络编程:基于C语言的简易代理服务器实现(proxylab)

2024-06-11 08:24| 来源: 网络整理| 查看: 265

这里写图片描述

本文记录了一个基于c socket的简易代理服务器的实现。(CS:APP lab 10 proxy lab)

本代理服务器支持keep-alive连接,将访问记录保存在log文件。

Github: https://github.com/He11oLiu/proxy

全文分为以下部分

HINT:CS:APP对服务器的要求 Part1:迭代服务器实现 & 简易处理(强制HTTP/1.0) Part2:并行服务器 & 互斥量 Part3:进一步理解HTTP协议,修改处理函数使其支持keep-alive Part4:readn与writen的优化 Q&A :出现的问题及解决方法 HINT [x] Be careful about memory leaks. When the processing for an HTTP request fails for any reason, the thread must close all open socket descriptors and free all memory resources before terminating. [x] You will find it very useful to assign each thread a small unique integer ID (such as the current requestnumber) and then pass this ID as one of the arguments to the thread routine. If you display this ID ineach of your debugging output statements, then you can accurately track the activity of each thread. [x] To avoid a potentially fatal memory leak, your threads should run as detached, not joinable (CS:APP 13.3.6). [x] Since the log file is being written to by multiple threads, you must protect it with mutual exclusion semaphores wdfhenever you write to it (CS:APP 13.5.2 and 13.5.3). [x] Be very careful about calling thread-unsafe functions such as inet ntoa, gethostbyname, and gethostbyaddr inside a thread. In particular, the open clientfd function in csapp.c is thread-unsafe because it calls gethostbyaddr, a Class-3 thread unsafe function (CSAPP 13.7.1).You will need to write a thread-safe version of open clientfd, called open_clientfd_ts, that uses the lock-and-copy technique (CS:APP 13.7.1) when it calls gethostbyaddr. [x] Use the RIO (Robust I/O) package (CS:APP 11.4) for all I/O on sockets. Do not use standard I/O onsockets. You will quickly run into problems if you do. However, standard I/O calls such as fopenand fwrite are fine for I/O on the log file. [x] The Rio_readn, Rio_readlineb, and Rio writen error checking wrappers in csapp.c arenot appropriate for a realistic proxy because they terminate the process when they encounter an error. Instead, you should write new wrappers called Rio readn w, Rio readlineb w, and Rio writen w that simply return after printing a warning message when I/O fails. When either of the read wrappers detects an error, it should return 0, as though it encountered EOF on the socket. [x] Reads and writes can fail for a variety of reasons. The most common read failure is an errno =ECONNRESET error caused by reading from a connection that has already been closed by the peeron the other end, typically an overloaded end server. The most common write failure is an errno =EPIPE error caused by writing to a connection that has been closed by its peer on the other end. This can occur for example, when a user hits their browser’s Stop button during a long transfer. [x] Writing to connection that has been closed by the peer first time elicits an error with errno set to EPIPE. Writing to such a connection a second time elicits a SIGPIPE signal whose default action isto terminate the process. To keep your proxy from crashing you can use the SIGIGN argument to th esignal function (CS:APP 8.5.3) to explicitly ignore these SIGPIPE signals Part 1

Implementing a Sequential Web Proxy

简易proxy lab雏形

服务器框架

int main(int argc, char **argv){ int lisenfd, port; unsigned int clientlen; clientinfo* client; /* Ignore SIGPIPE */ Signal(SIGPIPE, SIG_IGN); if (argc != 2){ fprintf(stderr, "usage:%s \n", argv[0]); exit(1); } port = atoi(argv[1]); /* open log file */ logfile = fopen("proxylog","w"); lisenfd = Open_listenfd(port); clientlen = sizeof(struct sockaddr_in); while (1){ /* Create a new memory area to pass arguments to doit */ /* It will be free by doit */ client = (clientinfo*)Malloc(sizeof(clientinfo)); client->socketfd = Accept(lisenfd, (SA *)&client->clientaddr, &clientlen); printf("Client %s connected\n",inet_ntoa(client->clientaddr.sin_addr)); doit(client); } return 0; }

作为最初版本,先完成一个迭代服务器,而非并行服务器,这类服务器的框架相对简单,这个部分主要测试对于期功能的理解,并在只针对一个用户接入的情况下进行处理。

服务器框架可简化为如下,其中doit()为实际处理客户端请求的函数。

init_server(); while(1){ accept(); doit(); } doit()处理客户端的请求

对于代理的处理条例很清晰

获取从客户发来的HTTP请求 拆解其中的uri 连接服务器,并重新发送H


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有