网络编程之使用DNS来解析Name的TCP Server和Client(二)
2018-03-21 21:09
453 查看
前言
本篇使用的代码是以前网络编程之I_O Multiplexing总结(四)的修改版,增加对主机和服务名字的解析。其他保持不变。1. TCP Client
#include <sys/socket.h> #include <sys/un.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <err.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h> #include <netdb.h> #define MAXLINE 20 #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) ssize_t writen(int fd, const void *vptr, size_t n); void str_cli(FILE *fp, int sockfd); int max(int,int); int main(int argc, char **argv) { int sockfd,err; struct sockaddr_in servaddr; char strcliaddr[INET_ADDRSTRLEN]; if (argc != 3) errx(1,"usage: tcpcli <hostname> <service>"); struct addrinfo hints, *res, *ressave; bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; if ((err=getaddrinfo(argv[1], argv[2], &hints, &res)) != 0) errx(1,"getaddrinfo error for %s", gai_strerror(err)); ressave = res; do { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) continue; /* ignore this one */ if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) break; /* success */ else perror("connect"); if(close(sockfd) == -1) handle_error("close"); } while ( (res = res->ai_next) != NULL); if (res == NULL) /* errno set from final connect() */ errx(1,"no valid host address for %s",argv[1]); freeaddrinfo(ressave); str_cli(stdin, sockfd); exit(0); } int max(int a,int b) { return a < b? b:a; } void str_cli(FILE *fp, int sockfd) { int maxfdp1, stdineof; fd_set rset; char buf[MAXLINE]; int n; stdineof = 0; FD_ZERO(&rset); for ( ; ; ) { if (stdineof == 0) FD_SET(fileno(fp), &rset); FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1; if(select(maxfdp1, &rset, NULL, NULL, NULL) == -1) handle_error("select"); if (FD_ISSET(sockfd, &rset)) { /* socket is readable */ if ( (n = read(sockfd, buf, MAXLINE)) < 0) handle_error("read"); if( n == 0){ if (stdineof == 1) return; /* normal termination */ else errx(1,"str_cli: server terminated prematurely"); } if( write(fileno(stdout), buf, n) == -1 ) handle_error("write stdio"); } if (FD_ISSET(fileno(fp), &rset)) { /* input is readable */ if ( (n = read(fileno(fp), buf, MAXLINE)) < 0) handle_error("read"); if(n == 0){ stdineof = 1; if(shutdown(sockfd, SHUT_WR)== -1) handle_error("shutdown");/* send FIN */ FD_CLR(fileno(fp), &rset); continue; } if(writen(sockfd, buf, n) == -1) handle_error("writen"); } } } ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else return (-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return (n); }
2. TCP Server
#include <sys/socket.h> #include <sys/un.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <errno.h> #include <err.h> #include <netdb.h> #define INET_ADDRSTRLEN 16 #define LISTENQ 10 #define SERV_PORT 9877 #define MAXLINE 20 #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) void str_echo(int sockfd); ssize_t writen(int fd, const void *vptr, size_t n); int main(int argc, char **argv) { int i, maxi, maxfd, listenfd, connfd, sockfd; int nready, client[FD_SETSIZE]; char strcliaddr[INET_ADDRSTRLEN]; ssize_t n; fd_set rset, allset; char buf[MAXLINE]; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; const int on = 1; struct addrinfo hints, *res, *ressave; int err; bzero(&hints, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; if (argc != 2) errx(1,"usage: daytimetcpsrv1 <service or port#>"); if ( (err=getaddrinfo(NULL, argv[1], &hints, &res)) != 0) errx(1,"getaddr error for %s", gai_strerror(err)); ressave = res; do { listenfd =socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (listenfd < 0) continue; /* error, try next one */ if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) handle_error("setsockopt"); if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) break; /* success */ if(close(listenfd) == -1) handle_error("close");/* bind error, close and try next one */ } while ( (res = res->ai_next) != NULL); if (res == NULL) /* errno from final socket() or bind() */ errx(1,"no valid host address information for %s", argv[1]); freeaddrinfo(ressave); if(listen(listenfd, LISTENQ) == -1) handle_error("listen"); maxfd = listenfd; /* initialize */ maxi = -1; /* index into client[] array */ for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; /* -1 indicates available entry */ FD_ZERO(&allset); FD_SET(listenfd, &allset); for ( ; ; ) { rset = allset; /* structure assignment */ if((nready=select(maxfd+1, &rset, NULL, NULL, NULL)) == -1) handle_error("select"); if (FD_ISSET(listenfd, &rset)) { /* new client connection */ clilen = sizeof(cliaddr); if((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) == -1 ) handle_error("accept"); for (i = 0; i < FD_SETSIZE; i++) if (client[i] < 0) { client[i] = connfd; /* save descriptor */ break; } if (i == FD_SETSIZE) errx(1,"too many clients"); if(inet_ntop(AF_INET,&cliaddr.sin_addr,strcliaddr,INET_ADDRSTRLEN) == NULL) handle_error("inet_pton"); printf("connected client number : %d, ipaddress:%s\n",i,strcliaddr); FD_SET(connfd, &allset); /* add new descriptor to set */ if (connfd > maxfd) maxfd = connfd; /* for select */ if (i > maxi) maxi = i; /* max index in client[] array */ if (--nready <= 0) continue; /* no more readable descriptors */ } for (i = 0; i <= maxi; i++) { /* check all clients for data */ if ( (sockfd = client[i]) < 0) continue; if (FD_ISSET(sockfd, &rset)) { if ( (n = read(sockfd, buf, MAXLINE)) < 0) handle_error("read"); if(n == 0){ if(getpeername(sockfd,(struct sockaddr *) &cliaddr, &clilen)== -1) handle_error("getpeername"); if(inet_ntop(AF_INET,&cliaddr.sin_addr,strcliaddr,INET_ADDRSTRLEN) == NULL) handle_error("inet_pton"); printf("closed client number : %d, ipaddress:%s\n",i,strcliaddr); if(close(sockfd) == -1) handle_error("close"); if(i == maxi) maxi-=1; FD_CLR(sockfd, &allset); client[i] = -1; } else if(writen(sockfd, buf, n) == -1) handle_error("writen"); if (--nready <= 0) break; /* no more readable descriptors */ } } } } void str_echo(int sockfd) { ssize_t n; char buf[MAXLINE]; again: while ( (n = read(sockfd, buf, MAXLINE)) > 0) if(writen(sockfd, buf, n) == -1) handle_error("writen"); if (n < 0 && errno == EINTR) goto again; else if (n < 0) errx(1,"str_echo: read error"); } ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else return (-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return (n); }
3. 运行结果
//首先在/etc/services中添加自己的service port myservice 9877/tcp tcpmux 1/tcp # TCP port service multiplexer tcpmux 1/udp # TCP port service multiplexer rje 5/tcp # Remote Job Entry rje 5/udp # Remote Job Entry echo 7/tcp echo 7/udp discard 9/tcp sink null discard 9/udp sink null [root@localhost ~]# ./11_ser myservice //执行server,此时看到使用的是service的name,而不是端口号
然后连接client,输入任意字符,最后输入
EOF:
//这里就可以使用host和service的名字了 [root@localhost ~]# ./11_cli localhost myservice hello boy, i am dhuang hello boy, i am dhuang //键入CTRL+D [root@localhost ~]# [root@localhost ~]# ./11_ser myservice connected client number : 0, ipaddress:127.0.0.1 closed client number : 0, ipaddress:127.0.0.1 //server此时继续等待新的连接到来
相关文章推荐
- Linux下网络编程(2)——TCP多连接,1个server,多个client
- Winsock网络编程笔记(2)----基于TCP的server和client
- dns解析IP过多使用TCP传输解析数据
- 使用TCPServer与TCPClient收发文件--转贴
- Qt一步步搭建TcpServer4——Client的封装与网络库的使用
- 使用java实现Server和Client(TCP)
- 禁止telnet和ssh中的client dnsname 反向解析
- 使用java实现Server和Client(TCP)
- 使用java实现Server和Client(TCP)
- Client-Server C程序示例C (使用 Sockets 和 TCP)
- VNX5700_DR Slot 2: The DNS client is unable to connect to name server
- 一个 ACE TCP Server/Client 例子
- 使用clientlistener和serverlistener刷新InlineFrame
- 基于C++的纯面向对象的通用高性能大并发TCP-SERVER/CLIENT开发框架实践系列之基础篇
- TCP Server《——》TCP Client
- TCP/IP 详解 卷1 ch14 DNS: The Domain Name System
- 使用Apache 的 FTP Client获取FTP服务器上的文件列表FTP response 421 received.Server closed connection问题的解决
- TCP-IP详解卷1-14:DNS(Domain Name System):域名系统
- TCPserver Tcpclient 怎么实现聊天室一起聊天的功能呢?
- DNS Server 的设置使用