Try   HackMD

Send HTTP GET and non-blocking connect

Author: WhoAmI
email: kccddb@gmail.com

Date: 20230517
Copyright: CC BY-NC-SA

思考 如何 改成 n 個 連線, 選一最快回應的?

POST 在 message-body 中傳送
GET 在 HTTP Request 中

/* Simple send http header non-blocking connect Author: WhoAmI DATE: 20230517 You may need getaddrinfo (Linux man 3), please STUDY DNS and the following four files /etc/host.conf resolver configuration file /etc/hosts host database file /etc/nsswitch.conf name service switch configuration /etc/gai.conf (configuration file) */ #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> /* superset of previous */ #include <string.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <arpa/inet.h> #include <sys/stat.h> #include <fcntl.h> #include <netdb.h> #include <arpa/inet.h> #include <netinet/in.h> //errno #include <errno.h> #define debugerr(x) x #define TRY 20 #define debugx(x) x /* HTTP client GET /index.html?ip=1234567&name=jone HTTP/1.1 Host: 127.0.0.1:9999 */ int getaddr(char *url, char *ipstr4, char *ipstr6) { struct addrinfo hints, *res, *p; int status; char ipstr[INET6_ADDRSTRLEN]; int count=0; memset(&hints, 0, sizeof hints); // = AF_UNSPEC; // AF_INET or AF_INET6 to force version hints.ai_family=AF_INET ; //IPv4 hints.ai_socktype = SOCK_STREAM; if ((status = getaddrinfo(url, NULL, &hints, &res)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); return 0; } debugx(printf("IP addresses for %s:\n\n", url)); for(p = res;p != NULL; p = p->ai_next) { void *addr; char *ipver; // get the pointer to the address itself, // different fields in IPv4 and IPv6: if (p->ai_family == AF_INET) { // IPv4 struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; addr = &(ipv4->sin_addr); ipver = "IPv4"; inet_ntop(p->ai_family, addr, ipstr4, sizeof ipstr); count++; } else { // IPv6 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); ipver = "IPv6"; if(ipstr6)inet_ntop(p->ai_family, addr, ipstr6, sizeof ipstr); debugx(printf(" %s: %s\n", ipver, ipstr)); } //inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); } freeaddrinfo(res); // free the linked list return count; } int setnonblock (int fd) { int flags; int n; flags = fcntl(fd, F_GETFL); //O_NONBLOCK=0x4000 fcntl(fd, F_SETFL, flags | O_NONBLOCK); n= fcntl(fd, F_GETFL) & O_NONBLOCK; return n; } int setblock (int fd) { int flags; int n; flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); n= fcntl(fd, F_GETFL) & O_NONBLOCK; return n; } int connecttcp(char *ip,int port,int msecs){ //EAGAIN, //EINTR:The system call was interrupted by a signal that was caught; int sockfd; struct sockaddr_in server_addr; socklen_t addrlen; int ret; int n; fd_set rfds,wfds; struct timeval tv; //int msecs=1000; int retval; int ok=0; int tryconnect=0; if((sockfd = socket(PF_INET, SOCK_STREAM, 0))<0){ perror("socket()"); exit(EXIT_FAILURE); } setnonblock(sockfd); memset(&server_addr,0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = inet_addr(ip); addrlen=sizeof(server_addr); n=1; do{ FD_ZERO(&wfds); FD_SET(sockfd, &wfds); tv.tv_sec = msecs/1000; tv.tv_usec =(tv.tv_sec*1000-msecs)*1000; retval = select(sockfd+1,NULL,&wfds, NULL, &tv);//for writing tryconnect++; //printf("retval=%d",retval); errno=0; ret=connect(sockfd, (struct sockaddr *)&server_addr,addrlen); if(ret<0){ //sleep(1); perror("connect"); debugerr(fprintf(stderr,"errno=%d, EINPROGRESS=%d,EISCONN=%d\n",errno,EINPROGRESS,EISCONN)); //connect: Operation now in progress //retval=1errno=119, 119 //EINPROGRESS //EISCONN =127 //Need select if(errno == EISCONN){ ok=!0; break; } if (errno == EINTR){ continue; } if (errno == EAGAIN ||errno==EINPROGRESS){ continue; } if (errno == ECONNREFUSED){ ok=0; break; } }else { ok=!0; break; } if(tryconnect >TRY){ ok=0; break; } }while(n>0); if(ok){ setblock(sockfd); debugerr(fprintf(stderr,"Connect to %s port %d, fd=%d\n",ip,port,sockfd)); return sockfd; } close(sockfd); debugerr(fprintf(stderr,"Cannot connect to %s port %d! close fd=%d \n",ip,port,sockfd)); return 0; } int main(int argc,char *argv[]) { int fd; //char buf[128]="GET /demox.html?ip=31.31.520.99&name=Sugar31 HTTP/1.1\r\nHost: 127.0.0.1:9999\r\n\r\n\r\n"; char buf[128]="GET /index.html?ip=31.31.520.99&name=Sugar31 HTTP/1.1\r\nHost: 127.0.0.1:9999\r\n\r\n\r\n"; char ret[1204]; int n; char ipv4[INET6_ADDRSTRLEN]; char *ip="127.0.0.1"; int port=80; int msec=1000; if(argc<2){ printf("usage: %s hostname \n",argv[0]); exit(EXIT_FAILURE ); } printf("%s %s\n",argv[0],argv[1]); getaddr(argv[1],ipv4,NULL); printf("Connect to %s:%d [msec:%d] and\nSend:\n%s\n",ipv4,port,msec,buf); fd=connecttcp(ipv4,port,msec); // setnonblock(fd); //setblock(fd); if(fd>0){ write(fd,buf,strlen(buf)); do{ memset(ret,0,sizeof(ret)); n=read(fd,ret,sizeof(ret)-1); if(n>0){ ret[n]=0; printf("--->%s\n",ret); }else break; }while(n>0); printf("close connection\n"); //sleep(10); close(fd); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE ); }