我有一个用C编写的代理服务器代码。该程序接受参数,例如google.com 9000 80然后在您的浏览器中inputlocalhost:9000获取google.com页面。 但是我希望能够一次创build几个隧道,但是我不知道该怎么做,因为主函数是无限循环的,这是工作程序的基础。
#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,' ',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,x; struct hostent *H; int on = 1; H = gethostbyname(host); if (!H) return (-2); len = sizeof(rem_addr); s = socket(AF_INET,0); if (s < 0) return s; setsockopt(s,4); len = sizeof(rem_addr); memset(&rem_addr,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,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,&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 portn",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; }
argc从哪里来?
C#阅读Windows Mobile宽带连接属性
访问DwmRegisterThumbnail的位数据
callback(C#)的概念
答案很简单:使用线程!
这里是一个教程如何做到这一点: http : //www.binarytides.com/server-client-example-c-sockets-linux/
处理多个连接的服务器的一些其他例子,如果你不喜欢线程: http : //martinbroadhurst.com/server-examples.html
如果你不想搞砸(在多线程代码中总是很容易),我推荐阅读这个问题的答案: 编写线程安全的UNIX代码的提示?
长话短说:您需要注意线程之间共享的任何变量,比如全局变量,静态变量和由指针传递的参数。 当两个线程尝试在同一位置写入数据(例如client_hostname全局变量),然后尝试从中读取数据时,必须避免出现这种情况,因为您最终可能会遇到一种情况,当您丢失其中一个值并且有两个线程来自两个不同的客户共享相同的主机名。
还要记住一件事情:我曾亲自见过的三个最好的C程序员认为多线程编程是他们工作中最困难的部分。 你现在正在处理复杂而复杂的问题。 如果你一开始失败,不要气馁,每个人起初都是这样做的。
另外,还有一点建议:不要混用两种不同的语言来命名变量。 既然你不能摆脱英语(因为图书馆是英文的),我建议你停止使用波兰语。 通常这是大多数公司的标准,只要在源代码中使用英文,即使它们位于非英语国家。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。