c - 如何充当客户端和服务器之间的代理?
问题描述
我正在编写一个程序,它应该充当 Web 服务器和浏览器之间的简单代理。浏览器连接到我的代理程序,我的程序连接到 Web 服务器。我的代理程序应该简单地将它从浏览器接收到的所有数据转发到 Web 服务器,反之亦然,无需以任何方式修改数据,也无需执行任何缓存。
我已经设法从网络服务器获得回复,但我如何将该回复定向到我的浏览器?还有什么方法可以将它放入某种我可以recv
并且随意的无限循环中send
?
编辑:
我几乎明白了。我只需要知道如何连续读取套接字。收到 Http 重定向后,程序意外关闭。
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#define SERVER_PORT 8080
#define SA struct sockaddr
#define MAX 80
pthread_t ptid, ptidd;
#define TRUE 1
#define FALSE 0
struct sockets_struct {
int server_sd;
int client_sd;
int new_sd;
}socks;
// Function designed to act as client.
void *client_func(void *sockets)
{
char buffer[MAX];
struct sockaddr_in servaddrr;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
int i, len, rc, on = 1;
//bzero(&servaddrr, sizeof(servaddrr));
// assign IP, PORT
servaddrr.sin_family = AF_INET;
servaddrr.sin_addr.s_addr = inet_addr("192.168.0.1");
servaddrr.sin_port = htons(80);
// connect the client socket to server socket
if (connect(socks->client_sd, (SA*)&servaddrr, sizeof(servaddrr)) != 0) {
printf(" client: connection with the server failed...\n");
exit(0);
}
else
printf(" client: connected to the remote server..\n");
do {
rc = recv(socks->client_sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" client: recv() failed\n");
}
break;
}
if (rc == 0) {
printf(" client: Connection closed\n");
break;
}
len = rc;
printf(" client: %d bytes received\n", len);
rc = send(socks->new_sd, buffer, len, 0);
if (rc < 0) {
perror(" client: send() failed");
break;
}
} while(TRUE);
}
// Function designed to act as server.
void *server_func(void *sockets)
{
int len, rc, on = 1;
int desc_ready, end_server = FALSE, compress_array = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in6 addr;
int timeout;
struct pollfd fds[200];
int nfds = 1, current_size = 0, i, j;
struct sockets_struct *socks = (struct sockets_struct*)sockets;
rc = setsockopt(socks->server_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0) {
perror(" server: setsockopt() failed\n");
close(socks->server_sd);
exit(-1);
}
rc = ioctl(socks->server_sd, FIONBIO, (char *)&on);
if (rc < 0) {
perror(" server: ioctl() failed\n");
close(socks->server_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(socks->server_sd, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0) {
perror(" server: bind() failed");
close(socks->server_sd);
exit(-1);
}
rc = listen(socks->server_sd, 32);
if (rc < 0) {
perror(" server: listen() failed");
close(socks->server_sd);
exit(-1);
}
memset(fds, 0 , sizeof(fds));
fds[0].fd = socks->server_sd;
fds[0].events = POLLIN;
timeout = (3 * 60 * 1000);
do {
printf(" server: waiting on poll()...\n");
rc = poll(fds, nfds, timeout);
if (rc < 0) {
perror(" server: poll() failed\n");
break;
}
if (rc == 0) {
printf(" server: poll() timed out. End program.\n");
break;
}
current_size = nfds;
for (i = 0; i < current_size; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN) {
printf(" server: Error! revents = %d\n", fds[i].revents);
end_server = TRUE;
break;
}
if (fds[i].fd == socks->server_sd) {
printf(" server: Listening socket is readable\n");
socks->new_sd = accept(socks->server_sd, NULL, NULL);
if (socks->new_sd < 0) {
if (errno != EWOULDBLOCK) {
perror(" server: accept() failed\n");
end_server = TRUE;
}
break;
}
printf(" server: new incoming connection - %d\n", socks->new_sd);
fds[nfds].fd = socks->new_sd;
fds[nfds].events = POLLIN;
nfds++;
}
else {
printf(" server: Descriptor %d is readable\n", fds[i].fd);
close_conn = FALSE;
do {
rc = recv(fds[i].fd, buffer, sizeof(buffer), 0);
if (rc < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
close_conn = TRUE;
}
break;
}
if (rc == 0) {
printf(" server: Connection closed\n");
close_conn = TRUE;
break;
}
len = rc;
printf(" server: %d bytes received \n", len);
rc = send(socks->client_sd, buffer, len, 0);
if (rc < 0) {
perror(" server: send() failed\n");
close_conn = TRUE;
break;
}
} while(TRUE);
if (close_conn) {
close(fds[i].fd);
fds[i].fd = -1;
compress_array = TRUE;
}
} /* End of existing connection is readable */
} /* End of loop through pollable descriptors */
} while (end_server == FALSE); /* End of serving running. */
}
int main (int argc, char *argv[])
{
socks.server_sd = socket(AF_INET, SOCK_STREAM, 0);
socks.client_sd = socket(AF_INET, SOCK_STREAM, 0);
if (socks.server_sd == -1) {
printf("socket \"server_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"server_sd\" successfully created..\n");
if (socks.client_sd == -1) {
printf("socket \"client_sd\" creation failed...\n");
exit(0);
}
else
printf("Socket \"client_sd\" successfully created..\n");
pthread_create(&ptidd, NULL, &client_func, &socks);
pthread_create(&ptid, NULL, &server_func, &socks);
pthread_join(ptidd, NULL);
return 0;
}
解决方案
您可以编写一个代理来理解它所代理的数据,也可以编写一个不理解它的代理。你的问题表明你想写一个没有的。这绝对是更简单的方法。
因此,一旦设置了所有连接,您有两件事要做。您需要从一个连接读取数据并将其发送到另一个连接。您还需要从另一个连接读取数据并将其发送到第一个连接。
使用两个线程是一种简单的方法。您还可fork
以为每个方向创建一个过程。但是每个人学习的第一个方法是一个select
或poll
循环。您可以将“选择循环代理”插入您最喜欢的搜索引擎以查找大量示例。
推荐阅读
- node.js - 在 express api 中使用节点集群总是有益的吗?
- java - 如何处理 MissingKotlinParameterException
- vue.js - 多选组件标签作为编号
- ffmpeg - 将带有时间线编辑(启用)的 ffmpeg 视频 delogo 过滤器应用于多个区域和多个时间帧不起作用
- r - 如何制作大表(由 3 个变量分隔)以显示第 4 个变量的百分比
- c - 为什么这个 C 代码输出 1 而不是 0?
- performance - hsflowd [2344]:SFF8036 ethtool ioctl 失败:没有这样的设备
- python - 正弦曲线拟合的问题:幅度和频率太低
- php - 如何使用 CodeIgniter 3 在路由文件中调用数据库?
- php - 在 PHP 中使用嵌套循环的素数