UNP 学习笔记 第十一章

一. 基础API的学习

1.本章四个API,和一个数据结构

1.getaddrinfo
2.getnameinfo
3.freeaddrinfo
4.gai_strerror

1.struct addrinfo

2.结合csapp的例子,自己写了一个测试代码,如下

功能

根据用户输入的host地址,找出对应的地址结构,再根据找到的地址结构,找出对应的host地址.
最后free掉这些addrinfo.
总结: 没啥用,就是熟悉一下三个api和struct addrinfo

源代码

#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define MAXLINE 8192 

int main(int argc,char ** argv)
{
  if(argc != 2)
  {
    printf("too few args\n");
    exit(0);
  }

  struct addrinfo hints,*listp,*p;
  char host[8192];

  bzero(&hints,sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = 0;
  
  getaddrinfo(argv[1],NULL,&hints,&listp);
 
  for( p = listp; p; p = p->ai_next)
  {
    getnameinfo((struct sockaddr*)p->ai_addr,p->ai_addrlen,host,MAXLINE,NULL,0,NI_NUMERICHOST); 

    printf("host = %s\n",host);
    printf(".....\n");
  }

  freeaddrinfo(listp);
  return 0;
}

二.与ipv6相关

1. ipv6的通配地址 0::1 , 0::0 以及	 sin6.sin6_addr = inaddr6_any
2. P.252  getaddrinfo 如何处理ipv4和ipv6

三.书上例子重点学习

1. tcp_connect
2. 时间获取客户程序. P.256
3. tcp_listen
4. 时间获取服务器程序 P.259  

四.并发服务器

主要改进

1. 加入了getaddrinfo 和 getnameinfo
2. 现在可以指定启动什么类型的服务器.但是有bug,ipv4的服务器只能IPv4访问,ipv6的可以用ipv4映射的ipv6访问,通配服务器 ipv6却无法访问,暂时不知为何.
3. 现在客户端和服务器都会显示对端的套接字了.
4. 

head.h

#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>

//some universal value
#define MAXSIZE 8392
#define MAXLINE 8392
#define SERV_PORT 8888
#define LISTENQ 100

typedef struct sockaddr SA;

//wrong proceedure

void err_str(const char* str)
{
  printf("<%s> is error!!\n",str);
  exit(0);// !> we also exit !
}

//wrap function
//socket 
int Socket(int family,int type,int protocol)
{
  int sockfd;
  if((sockfd = socket(family,type,protocol)) < 0)
    err_str("socket");
  return sockfd;
}

int Connect(int sockfd,const struct sockaddr* sa,socklen_t len)
{
  int ret;
  if((ret = connect(sockfd,sa,len)) < 0)
    err_str("connect");
  return ret;
}

int Bind(int sockfd,const struct sockaddr* sa,socklen_t len)
{
  int ret;
  if((ret = bind(sockfd,sa,len)) < 0)
    err_str("bind");
  return ret;
}

int Listen(int sockfd,int backlog)
{
  int ret;
  if((ret = listen(sockfd,backlog)) < 0)
    err_str("listen");
  return ret;
}

int Accept(int sockfd,struct sockaddr* cliaddr,socklen_t* len)
{
  int  connfd;
  if((connfd = accept(sockfd,cliaddr,len)) < 0)
    err_str("accept");
  return connfd;
}


//  IO 
//....no buffer version
ssize_t readn(int sockfd,char* buf,size_t nbytes)
{
  ssize_t nread;
  size_t nleft = nbytes;
  char* p = buf;

  while(nbytes)
  {
    if((nread = read(sockfd,p,nleft)) < 0)
    {
      if(errno == EINTR)
        nread = 0;
      else
        return -1;
    }
    else if(nread == 0)
      break;
    nleft -= nread;
    p += nread;
  }
  return (nbytes - nleft);
}

ssize_t writen(int sockfd,const char* buf,size_t nbytes)
{
  ssize_t nwrite;
  size_t nleft = nbytes;
  const char* bufp = buf;
  while(nleft > 0)
  {
    if((nwrite = write(sockfd,bufp,nleft)) <= 0)
    {
      if(nwrite < 0 && errno == EINTR)
        nwrite = 0;
      else
        return -1;
    }
    nleft -= nwrite;
    bufp += nwrite;
  }
  return nbytes;
}

ssize_t readline(int sockfd,char* buf,size_t n)
{
  ssize_t nread;
  char* p = buf;
  char c;
  size_t i;
  for(i = 1; i < n; ++i)
  {
    if((nread = read(sockfd,&c,1)) == 1)
    {
      *p++ = c;
      if(c == '\n')
        break;
    }else if(nread == 0){
      *p = '\0';
      return (i - 1);
    }else{
      if(errno == EINTR)
        continue;
      return -1;
    }
  }
  *p = '\0';
  return i;  
}




//change address
int Inet_pton(int family,const char* strptr,void* addrptr)
{
  int ret;
  if((ret = inet_pton(family,strptr,addrptr)) < 0)
    err_str("inet_pton");
  return ret;
}

//get information
int Getsockname(int sockfd,struct sockaddr* sa,socklen_t* addrlen)
{
  int ret;
  if((ret = getsockname(sockfd,sa,addrlen)) < 0)
      err_str("getsockname");
  return ret;
}

int Getpeername(int sockfd,struct sockaddr* sa,socklen_t* addrlen)
{
  int ret;
  if((ret = getpeername(sockfd,sa,addrlen)) < 0)
    err_str("getpeername");
  return ret;
}

int Getnameinfo(const struct sockaddr* addr,socklen_t addrlen,
    char* host,socklen_t hostlen,char* service,socklen_t servlen,int flags)
{
  int ret;
  if((ret = getnameinfo(addr,addrlen,host,hostlen,service,servlen,flags)) < 0)
    err_str(gai_strerror(errno));
  return ret;
}

int Getaddrinfo(const char* host,const char* port,const struct addrinfo* hints,struct addrinfo** res)
{
  int ret;
  if((ret = getaddrinfo(host,port,hints,res)) != 0)
    err_str(gai_strerror(errno));
  return ret;
}

char * sock_ntop(const struct sockaddr* sa,socklen_t len)
{
  char portstr[8];
  static char hoststr[128];

  switch(sa->sa_family)
  {

  case AF_INET:{
    struct sockaddr_in* sin = (struct sockaddr_in *)sa;
    if(inet_ntop(AF_INET,&sin->sin_addr,hoststr,sizeof(hoststr)) == NULL)
      return NULL;

    if(ntohs(sin->sin_port) != 0)
    {
      snprintf(portstr,sizeof(portstr),":%d",ntohs(sin->sin_port));
      strcat(hoststr,portstr); 
    }
    return hoststr;
               }

  case AF_INET6:{
    struct sockaddr_in6* sin6 = (struct sockaddr_in6* )sa;
    if((inet_ntop(AF_INET6,&sin6->sin6_addr,hoststr,sizeof(hoststr))) == NULL)
      return NULL;
    
    if(ntohs(sin6->sin6_port) != 0)
    {
      snprintf(portstr,sizeof(portstr),":%d",ntohs(sin6->sin6_port));
      strcat(hoststr,portstr);
    }
    return hoststr;
                }
  }
  return hoststr;
  len = len;//no use !
}

int open_client(const char* host,const char* serv)
{
  int sockfd;
  struct addrinfo hints,*listp,*p;
  
  bzero(&hints,sizeof(hints));
  
  hints.ai_family = AF_UNSPEC;//for both ipv4 && ipv6
  hints.ai_socktype = SOCK_STREAM;
  
  Getaddrinfo(host,serv,&hints,&listp);

  for(p = listp; p != NULL; p = p->ai_next)
  {
    if((sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) < 0)
      continue;
    if((connect(sockfd,p->ai_addr,p->ai_addrlen)) == 0)
      break;
    close(sockfd);    //dont forget close sockfd.
  }
  freeaddrinfo(listp);
  return sockfd;
}

//open serv .we can use ipv4 or ipv6
//flags = 0 ,universal.flags = 1,IPV4,flags = 2,IPV6
int open_serv(const char* host,const char* serv,const int flags)
{
  int sockfd;
  struct addrinfo hints,*listp,*p;
  const int on = 1;

  bzero(&hints,sizeof(hints));
  hints.ai_flags = AI_PASSIVE;
  
  if(flags == 0)
    hints.ai_family = AF_UNSPEC;
  else if(flags == 1)
    hints.ai_family = AF_INET;
  else
    hints.ai_family = AF_INET6;

  hints.ai_socktype = SOCK_STREAM;

  Getaddrinfo(host,serv,&hints,&listp);
  
  for(p = listp; p ; p = p->ai_next)
  {
    if((sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) < 0)
    {
      continue;
    }
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    if( ( bind(sockfd,p->ai_addr,p->ai_addrlen) ) == 0)
    {
      //printf("bind to %d successful!\n",sockfd);
      break;
    }
    close(sockfd);
  }
  if( p == NULL)
    err_str("No available address");
  Listen(sockfd,LISTENQ);
  freeaddrinfo(listp);
  return sockfd;
}

client.c

#include "head.h"

int main(int argc,char** argv)
{
  if(argc < 3){
    printf("Please enter IP address and port.\n");
    exit(0);
  }

  struct sockaddr_storage ss;
  socklen_t len;
  int sockfd; //client sockfd
  sockfd = open_client(argv[1],argv[2]);
  len = sizeof(ss);
  if(getpeername(sockfd,(SA*)&ss,&len) < 0)
   err_str("getpeername");

  printf("You have connected to %s\n",sock_ntop((SA*)&ss,len));
  
  // now do some echo
  //demand client to enter some words
  char buf[MAXSIZE];
  for( ; ;)
  {
    fgets(buf,MAXLINE,stdin);
    if(( writen(sockfd,buf,strlen(buf))) < 0)
      err_str("writen");
    bzero(buf,sizeof(buf));
  }
  return 0;
}

serv.c

#include "head.h"

int main(int argc,const char**argv)
{
  if(argc != 2)
  {
    fprintf(stderr,"enter 1(ipv4 only),2(ipv6 only),0(both) to start service!\n");
    exit(0);
  }

  struct sockaddr_in cli;
  socklen_t len;
  int sockfd,connfd;
  char buf[MAXSIZE];

  sockfd = open_serv(NULL,"8888",(*argv[1] - '0'));

  printf("*********************wait for connection*************\n");
  len = sizeof(cli);
  connfd = Accept(sockfd,(SA* )&cli,&len);
  
  Getpeername(connfd,(SA*)&cli,&len); 
  char *cli_info = sock_ntop((SA*)&cli,len);
  printf("%s connected!\n",cli_info);

  while(1)
  {
    if((readline(connfd,buf,MAXLINE)) > 0)
    { 
      fputs(buf,stdout);
      bzero(buf,sizeof(buf));
    }
    else
      break;
  }
  
  return 0;
}

效果展示

在这里插入图片描述

五. 可重入

结合APUE

浅谈可重入

malloc与可重入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值