一. 基础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>
#define MAXSIZE 8392
#define MAXLINE 8392
#define SERV_PORT 8888
#define LISTENQ 100
typedef struct sockaddr SA;
void err_str ( const char * str)
{
printf ( "<%s> is error!!\n" , str) ;
exit ( 0 ) ;
}
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;
}
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;
}
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;
}
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;
}
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;
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) ;
}
freeaddrinfo ( listp) ;
return sockfd;
}
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 )
{
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;
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) ) ;
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与可重入