目錄表

Network IPC:Socket

0x00 Outline


0x01 Introduction


0x02 Socket Descriptors

socket descriptor

#include <sys/types.h>
#include <sys/socket.h>
 
int socket(int domain, int type, int protocol);
/*return file (socket) descriptor if success, or -1 on error*/

Socket Descriptors and File I/O Functions

Release a socket descriptor

#include <sys/socket.h>
 
int shutdown(int socket, int how);
/*returns 0 if success, or -1 on error*/

0x03 Addressing

identify socket

byte ordering

#include <arpa/inet.h>
 
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

address formats

/*On Linux*/
struct sockaddr
{
    sa_family_t sa_family;    /* address family */
    char sa_data[14];         /* variable-length address */
};
 
/*On some other system*/
struct sockaddr
{
    unsigned char sa_len;     /* total length */
    sa_family_t sa_family;    /* address family */
    char sa_data[14];         /* variable-length address */
};
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
 
struct in_addr
{
    in_addr_t s_addr;           /* IPv4 address */
};
 
struct sockaddr_in
{
    sa_family_t sin_family;     /* address family */
    in_port_t sin_port;         /* port number */
    struct in_addr sin_addr;    /* IPv4 address */
    unsigned char sin_zero[8];
};
typedef uint16_t in_port_t;
struct in6_addr
{
    union
    {                                /* IPv4 address */
        uint8_t __u6_addr8[16];
        uint16_t __u6_addr16[8];
        uint32_t __u6_addr32[4];
    } __in6_u;
};
 
struct sockaddr_in6
{
    sa_family_t sin_family;                /* address family */
    in_port_t sin6_port;                   /* port number */
    uint32_t sin6_flowinfo;                /* IPv6 flow info */
    struct in6_addr sin6_addr;             /* IPv6 address */
    uint32_t sin6_scope_id;                /* IPv6 scope id */
};

conversion of address

#include <arpa/inet.h>
 
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
/*Returns: pointer to address string on success, or NULL on error*/
#include <arpa/inet.h>
 
int inet_pton(int af, const char *src, void *dst);
/*Returns: 1 on success, 0 if the format is invalid, or -1 on error and errno=EAFNOSUPPORT*/
if(inet_pton(AF_INET, argv[1], &addr4) == 1)
{
    printf("IPv4: 0x%08x\n", htonl(addr4.s_addr));
}
 
if(inet_pton(AF_INET6, argv[1], &addr6) == 1)
{
    printf("IPv6: 0x%08x%08x%08x%08x\n",
        htonl(addr6.__in6_u.__u6_addr32[0]),
        htonl(addr6.__in6_u.__u6_addr32[1]),
        htonl(addr6.__in6_u.__u6_addr32[2]),
        htonl(addr6.__in6_u.__u6_addr32[3]));
}

address lookup

struct hostent
{
    char *h_name;          /*official name of host*/
    char **h_aliases;      /* alias list */
    int h_addrtype;        /* host address type */
    int h_length;          /* length of address */
    char **h_addr_list;    /* list of addresses */
}
/* for AF_INET */
#include <sys/socket.h>
 
struct hostent *gethostent(void);
/*Returns: valid pointer if success, or NULL on error*/
 
void sethostent(int stayopen);
void endhostent(void);
int main()
{
    int i;
    char buf[64];
    struct hostent *h;
 
    while((h = gethostent()) != NULL)
    {
        if(h->h_addrtype != AF_INET)
            continue;
        printf(“name=%s, addr={, h->h_name);
 
        for(i = 0; h->h_addr_list[i] != NULL; i++)
        {
            printf("%s ", inet_ntop(AF_INET, h->h_addr_list[i], buf, sizeof(buf)));
        }
 
        printf("}\n");
    }
 
    return(0);
}
name=cshome.cs.nctu.edu.tw, addr={ 140.113.235.101 }
name=csduty.cs.nctu.edu.tw, addr={ 140.113.235.102 }
truct protoent
{
    char *p_name;        /*officialprotocolname*/
    char **p_aliases;    /* alias list */
    int p_proto;         /* protocol number */
}
#include <netdb.h>
 
struct protoent *getprotoent(void);
/*Returns: valid pointer if success, or NULL on error*/
 
struct protoent *getprotobyname(const char *name);
/*returns a protoent structure for the entry from the database that matches the protocol name,NULL on error*/
 
struct protoent *getprotobynumber(int proto);
/*returns a protoent structure for the entry from the database that matches the protocol number,NULL on error*/
 
void setprotoent(int stayopen);
void endprotoent(void);
int main()
{
    int i;
    struct protoent *p;
 
    while((p = getprotoent()) != NULL)
    {
        printf("name=%s (%d), ", p->p_name, p->p_proto);
        printf("alias={ ");
 
        for(i = 0; p->p_aliases[i] != NULL; i++)
        {
            printf("%s ", p->p_aliases[i]); printf("}\n");
        }
    }
 
    return(0);
}
name=ip (0), alias={ IP }
name=icmp (1), alias={ ICMP }
name=igmp (2), alias={ IGMP }
...
name=tcp (6), alias={ TCP }
...
name=udp (17), alias={ UDP }
...
struct servent
{
    char *s_name;      /*officialservicename*/
    char **S_aliases;  /* alias list */
    int s_port;        /* port number */
    char *s_proto;     /*protocoltouse*/
}
#include <netdb.h>
 
struct servent *getservent(void);
/*Returns: valid pointer if success, or NULL on error*/
 
struct servent *getservbyname(const char *name, const char *proto);
/*returns a servent structure for the entry from the database that matches the service name using protocol proto, or NULL on error*/
 
struct servent *getservbyport(int port, const char *proto);
/*returns a servent structure for the entry from the database that matches the service port(network byte order) using protocol proto, or NULL on error*/
 
void setservent(int stayopen);
 
void endservent(void);
int main()
{
    int i;
    struct servent *s;
 
    while((s = getservent()) != NULL)
    {
        printf("name=%s (%s/%d), ", s->s_name, s->s_proto, ntohs(s->s_port));
        printf("alias={ ");
 
        for(i = 0; s->s_aliases[i] != NULL; i++)
        {
            printf("%s ", s->s_aliases[i]); printf("}\n");
        }
    }
    return(0);
}
...
name=telnet (tcp/23), alias={ }
name=ftp (tcp/21), alias={ }
name=pop3 (tcp/110), alias={ pop-3 }
name=www (tcp/80), alias={ http }
...
#include <netdb.h>
extern int h_errno;
 
struct hostent *gethostbyname(const char *name);
/*Returns: valid pointer if success, or NULL on error*/
 
#include <sys/socket.h>
 
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type);
/*Returns: valid pointer if success, or NULL on error*/

thread-safe query

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
 
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
/*Returns: zero if success, or nonzero error code on error*/
struct addrinfo
{
    int ai_flags;
    int ai_family;
    int ai_socktype;
    int ai_protocol;
    size_t ai_addrlen;
    struct sockaddr *ai_addr;
    char *ai_canonname;
    struct addrinfo *ai_next;
};
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
 
const char *gai_strerror(int error);
int main(int argc, char *argv[])
{
    int s;
    struct addrinfo hints, *result, *rp;
 
    if (argc < 3)
    {
        fprintf(stderr, "usage: %s host port\n", argv[0]);
        exit(-1);
    }
 
    bzero(&hints, sizeof(struct addrinfo));
    hints.ai_family = AF_INET;                 /* allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;           /* stream socket */
    hints.ai_flags = 0;
    hints.ai_protocol = 0;                     /* any protocol */
 
    if((s=getaddrinfo(argv[1], argv[2], &hints, &result))!=0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
        exit(-1);
    }
 
    for(rp = result; rp != NULL; rp = rp->ai_next)
    {
        struct sockaddr_in *p = (struct sockaddr_in*) rp->ai_addr;
        printf( "%s:%d\n", inet_ntoa(p->sin_addr), ntohs(p->sin_port));
    }
 
    return(0);
}
$ ./getaddrinfo google.com www
74.125.45.100:80
209.85.171.100:8
74.125.67.100:80
int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
/*Returns:zero if success,or nonzero on error*/
int main(int argc, char *argv[])
{
    struct sockaddr_in sin;
    char host[64], serv[64];
    int s;
 
    if (argc < 3)
    {
        fprintf(stderr, "usage: %s ip port\n", argv[0]);
        exit(-1);
    }
 
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(argv[1]);
    sin.sin_port = htons(atoi(argv[2]));
 
    if((s = getnameinfo((struct sockaddr*) &sin, sizeof(sin), host, sizeof(host), serv, sizeof(serv), 0)) != 0)
    {
        fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));
        exit(-1);
    }
 
    printf("%s:%s\n", host, serv);
    return(0);
}

0x04 Connection Establishment

server connect step

client connect step

socket function

#include <sys/socket.h>
 
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
/*Returns: zero if success, or -1 on error*/
#include <sys/socket.h>
 
int connect(int socket, const struct sockaddr *address, socklen_t address_len);
/*Returns: zero if success, or -1 on error*/
#include <sys/socket.h>
 
int listen(int socket, int backlog);
/*Returns: zero if success, or -1 on error*/
#include <sys/socket.h>
 
int accept(int sockfd, struct sockaddr *restrict address, socklen_t *restrict address_len);
/*Returns: file (socket) descriptor if success, or -1 on error*/
#include <sys/socket.h>
 
int getsockname(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
int getpeername(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);

0x05 Data Transfer

send data

#include <sys/socket.h>
 
ssize_t send(int socket, const void *buffer, size_t length, int flags);
ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
/*Returns: number of bytes sent if success, or -1 on error*/

receive data

#include <sys/socket.h>
 
ssize_t recv(int socket, void *buffer, size_t length, int flags);
ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
/*Returns: number of bytes received if success, 0 if no messages are available and peer has done an orderly shutdown, or -1 on error*/

0x06 Socket Option

#include <sys/socket.h>
 
int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len);
/*Returns: zero if success, or -1 on error*/

0x06 參考資料