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*/
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
/etc/hosts
檔案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 }
/etc/protocols
檔案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 } ...
/etc/services
檔案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); }
server connect step
bind
到 socket descriptorlisten
for incoming connectionaccept
incoming connectionclient connect step
connect
to serversocket 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);
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*/
#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*/