您的位置:首页 > 理论基础 > 计算机网络

网络编程之使用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此时继续等待新的连接到来
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: