[英]Proxy server in C - Multiple
I have a proxy server code written in C. The program accepts arguments, eg google.com 9000 80 And then in your browser as you enter localhost: 9000 get google.com page. 我有一个用C编写的代理服务器代码。该程序接受参数,例如google.com 9000 80然后在您输入localhost:9000 get google.com页面时在浏览器中。 But I'd like to be able to create several tunnels at once but I do not know how to do it, because in the main function is infinite loop on of which is the basis of the work program. 但我希望能够一次创建多个隧道,但我不知道该怎么做,因为在main函数中是无限循环,其中是工作程序的基础。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/ftp.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#define BUF_SIZE 4096
extern int sys_nerr, errno;
char client_hostname[64];
void set_nonblock(int fd)
{
int fl;
int x;
x = fcntl(fd, F_GETFL, &fl);
if (x < 0) {
exit(1);
}
fl |= O_NONBLOCK;
x = fcntl(fd, F_SETFL, &fl);
if (x < 0) {
exit(1);
}
}
int serwer_gniazdo(char *addr, int port)
{
int addrlen, s, on = 1, x;
static struct sockaddr_in client_addr;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
perror("socket"), exit(1);
addrlen = sizeof(client_addr);
memset(&client_addr, '\0', addrlen);
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = inet_addr(addr);
client_addr.sin_port = htons(port);
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 4);
x = bind(s, (struct sockaddr *) &client_addr, addrlen);
if (x < 0)
perror("bind"), exit(1);
x = listen(s, 5);
if (x < 0)
perror("listen"), exit(1);
return s;
}
int otworz_host(char *host, int port)
{
struct sockaddr_in rem_addr;
int len, s, x;
struct hostent *H;
int on = 1;
H = gethostbyname(host);
if (!H)
return (-2);
len = sizeof(rem_addr);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
return s;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 4);
len = sizeof(rem_addr);
memset(&rem_addr, '\0', len);
rem_addr.sin_family = AF_INET;
memcpy(&rem_addr.sin_addr, H->h_addr, H->h_length);
rem_addr.sin_port = htons(port);
x = connect(s, (struct sockaddr *) &rem_addr, len);
if (x < 0) {
close(s);
return x;
}
set_nonblock(s);
return s;
}
int sock_addr_info(struct sockaddr_in addr, int len, char *fqdn)
{
struct hostent *hostinfo;
hostinfo = gethostbyaddr((char *) &addr.sin_addr.s_addr, len, AF_INET);
if (!hostinfo) {
sprintf(fqdn, "%s", inet_ntoa(addr.sin_addr));
return 0;
}
if (hostinfo && fqdn)
sprintf(fqdn, "%s [%s]", hostinfo->h_name, inet_ntoa(addr.sin_addr));
return 0;
}
int czekaj_na_polaczenie(int s)
{
int newsock;
static struct sockaddr_in peer;
socklen_t len;
len = sizeof(struct sockaddr);
newsock = accept(s, (struct sockaddr *) &peer, &len);
if (newsock < 0) {
if (errno != EINTR)
perror("accept");
}
sock_addr_info(peer, len, client_hostname);
set_nonblock(newsock);
return (newsock);
}
int zapis(int fd, char *buf, int *len)
{
int x = write(fd, buf, *len);
if (x < 0)
return x;
if (x == 0)
return x;
if (x != *len)
memmove(buf, buf+x, (*len)-x);
*len -= x;
return x;
}
void klient(int cfd, int sfd)
{
int maxfd;
char *sbuf;
char *cbuf;
int x, n;
int cbo = 0;
int sbo = 0;
fd_set R;
sbuf = (char *)malloc(BUF_SIZE);
cbuf = (char *)malloc(BUF_SIZE);
maxfd = cfd > sfd ? cfd : sfd;
maxfd++;
while (1)
{
struct timeval to;
if (cbo)
{
if (zapis(sfd, cbuf, &cbo) < 0 && errno != EWOULDBLOCK) {
exit(1);
}
}
if (sbo) {
if (zapis(cfd, sbuf, &sbo) < 0 && errno != EWOULDBLOCK) {
exit(1);
}
}
FD_ZERO(&R);
if (cbo < BUF_SIZE)
FD_SET(cfd, &R);
if (sbo < BUF_SIZE)
FD_SET(sfd, &R);
to.tv_sec = 0;
to.tv_usec = 1000;
x = select(maxfd+1, &R, 0, 0, &to);
if (x > 0) {
if (FD_ISSET(cfd, &R)) {
n = read(cfd, cbuf+cbo, BUF_SIZE-cbo);
if (n > 0) {
cbo += n;
} else {
close(cfd);
close(sfd);
_exit(0);
}
}
if (FD_ISSET(sfd, &R)) {
n = read(sfd, sbuf+sbo, BUF_SIZE-sbo);
if (n > 0) {
sbo += n;
} else {
close(sfd);
close(cfd);
_exit(0);
}
}
} else if (x < 0 && errno != EINTR) {
close(sfd);
close(cfd);
_exit(0);
}
}
}
int main(int argc, char *argv[])
{
char *localaddr = (char *)"127.0.0.1";
int localport = atoi(argv[1]);
char *remoteaddr = (char *)(argv[2]);
int remoteport = atoi(argv[3]);
int client, server;
int master_sock;
if (4 != argc)
{
fprintf(stderr, "usage: %s port host port\n", argv[0]);
exit(1);
}
assert(localaddr);
assert(localport > 0);
assert(remoteaddr);
assert(remoteport > 0);
master_sock = serwer_gniazdo(localaddr, localport);
for (;;)
{
if ((client = czekaj_na_polaczenie(master_sock)) < 0)
continue;
if ((server = otworz_host(remoteaddr, remoteport)) < 0)
continue;
if (!fork()) {
klient(client, server);
}
close(client);
close(server);
}
printf("Koniec programu");
return 0;
}
The answer is simple: use threads! 答案很简单:使用线程!
Here is a tutorial how to do it: http://www.binarytides.com/server-client-example-c-sockets-linux/ 以下是如何操作的教程: http : //www.binarytides.com/server-client-example-c-sockets-linux/
Some other examples of servers handling multiple connections, if you don't like threads: http://martinbroadhurst.com/server-examples.html 如果您不喜欢线程,则处理多个连接的服务器的其他一些示例: http : //martinbroadhurst.com/server-examples.html
And if you don't want mess things up (which is always easy in multithreaded code), I recommend reading answer to this question: Tips to write thread-safe UNIX code? 如果你不想搞砸(在多线程代码中总是很容易),我建议你阅读这个问题的答案: 编写线程安全的UNIX代码的提示?
To make long story short: you need to watch out for any variable that is shared between threads, like globals, statics and arguments passed by pointer. 长话短说:你需要注意线程之间共享的任何变量,比如全局变量,静态和指针传递的参数。 You must avoid situations, when two threads try to write in the same place (for example client_hostname global variable) and then try to read from it, because you may end up with a situation, when you loose one of the values and have two threads from two different clients sharing the same hostname. 当两个线程尝试在同一个地方写入时(例如client_hostname全局变量)然后尝试从中读取,你必须避免出现这种情况,因为当你松开其中一个值并且有两个线程时,你可能会遇到这种情况来自两个不同的客户端共享相同的主机名。
Also keep in mind one more thing: three best C programmers I have ever met in person consider multithreading programming as the most difficult part of their job. 还要记住一件事:我遇到过的三位最好的C程序员都认为多线程编程是他们工作中最困难的部分。 You are now tackling complicated and complex problem. 您现在正在解决复杂而复杂的问题。 Don't be discouraged if you failed at first, everyone did at first. 如果你一开始失败,不要气馁,每个人一开始都这样做。
Also, a bit of advice: never mix up two different languages for naming variables. 另外,一些建议:永远不要混淆两种不同的语言来命名变量。 Since you can't get rid of English (because libraries are in English), I advise you to stop using Polish words. 由于你无法摆脱英语(因为图书馆是英文的),我建议你不要使用波兰语。 Usually it is a standard in most companies to only use English in their source code anyway - even if they are located in non-English speaking country. 通常,大多数公司的标准是在源代码中仅使用英语 - 即使它们位于非英语国家。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.