/* 建立一個套接字 */ #include <sys/socket.h> int socket(int domain, int type, int protocol);
#include <sys/socket.h> int shutdown(int sockfd, int how);
#include <arpa/inet.h> uint32_t htonl(uint32_t hostint32); // 返回值:以網絡字節序表示的32位整型數 uint16_t htons(uint16_t hostint16); // 返回值:以網絡字節序表示的16位整型數 uint32_t ntohl(uint32_t netint32); // 返回值:以主機字節序表示的32位整型數 uint16_t ntohl(uint16_t netint16); // 返回值:以主機字節序表示的16位整型數
struct sockaddr { sa_family_t sa_family; /* address family */ char sa_data[14]; /* variable-length address */ };
在IPv4 套接字地址結構 sockaddr_in (in表示internet網絡):算法
struct in_addr { in_addr_in 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]; };
二進制地址格式和 點分十進制格式轉換:編程
#include <arpa/inet.h> const char* inet_ntop(int domain, const char* addr, char* str, socklen_t size); int inet_pton(int domain, const char* str, void* str);
#include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char* host, const char* service, const struct addrinfo* hint, struct addrinfo* res); void freeaddrinfo(struct addrinfo* ai);
struct addrinfo { int ai_flags; /* customize behavior */ int ai_family; /* address family */ int ai_socktype; /* socket type */ int ai_protocol; /* protocol */ socklen_t ai_addrlen; /* length in bytes of address */ struct sockaddr* ai_addr; /* address */ char* ai_canonname; struct addrinfo* ai_next; /* next in list */ .... };
#include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <stdio.h> void print_family(struct addrinfo* aip) { fprintf(stdout, "family:"); switch (aip->ai_family) { case AF_INET: fprintf(stdout, "inet"); break; case AF_INET6: fprintf(stdout, "inet6"); break; case AF_UNIX: fprintf(stdout, "unix"); break; case AF_UNSPEC: fprintf(stdout, "unspecfied"); break; default: fprintf(stdout, "unknown"); } } void print_type(struct addrinfo* aip) { fprintf(stdout, "type"); switch (aip->ai_socktype) { case SOCK_STREAM: fprintf(stdout, "stream"); break; case SOCK_DGRAM: fprintf(stdout, "datagram"); break; case SOCK_SEQPACKET: fprintf(stdout, "seqpacket"); break; case SOCK_RAW: fprintf(stdout, "raw"); break; default: fprintf(stdout, "unknown (%d)", aip->ai_socktype); } } void print_protocol(struct addrinfo* aip) { fprintf(stdout, "protocol"); switch (aip->ai_protocol) { case 0: fprintf(stdout, "default"); break; case IPPROTO_TCP: fprintf(stdout, "tcp"); break; case IPPROTO_UDP: fprintf(stdout, "udp"); break; case IPPROTO_RAW: fprintf(stdout, "raw"); break; default: fprintf(stdout, "unknown (%d)", aip->ai_protocol); } } void print_flags(struct addrinfo* aip) { fprintf(stdout, "flags"); if (aip->ai_flags == 0) { fprintf(stdout, "0"); } else { if (aip->ai_flags & AI_PASSIVE) { fprintf(stdout, "passive"); } if (aip->ai_flags & AI_CANONNAME) { fprintf(stdout, "canon"); } if (aip->ai_flags & AI_NUMERICHOST) { fprintf(stdout, "numhost"); } } } int main(int argc, char* argv[]) { struct addrinfo* ailist = NULL; struct addrinfo* aip = NULL; struct addrinfo hint; struct sockaddr_in* sinp; const char* addr = NULL; char abuf[INET_ADDRSTRLEN]; if (argc != 3) { fprintf(stdout, "usage:%s <hostname> <service>", argv[0]); return 1; } hint.ai_flags = AI_CANONNAME; hint.ai_family = 0; hint.ai_socktype = 0; hint.ai_protocol = 0; hint.ai_addrlen = 0; hint.ai_canonname = NULL; hint.ai_addr = NULL; hint.ai_next = NULL; int ret = getaddrinfo(argv[1], argv[2], &hint, &ailist); if (ret != 0) { fprintf(stderr, "getaddrinfo error\n"); return 1; } for (aip = ailist; aip != NULL; aip = aip->ai_next) { print_flags(aip); print_family(aip); print_type(aip); print_protocol(aip); fprintf(stdout, "\n\thost %s", aip->ai_canonname ? aip->ai_canonname : '-'); if (aip->ai_family == AF_INET) { sinp = (struct sockaddr_in*)aip->ai_addr; addr = inet_ntop(AF_INET, &sinp->sin_addr, abuf, INET_ADDRSTRLEN); fprintf(stdout, "address %s", addr ? addr : "unknown"); fprintf(stdout, "port %d", ntohs(sinp->sin_port)); } fprintf(stdout, "\n"); } return 0; }
套接字與地址綁定:服務器
#include <sys/socket.h> int bind(int sockfd, const struct sockaddr* addr, socklen_t len);
#include <sys/socket.h> int connect(int sockfd, const struct sockaddr* addr, socklen_t len);
#include <sys/socket.h> #define MAXSLEEP 128 int connect_retry(int sockfd, const struct sockaddr* addr, socklen_t len) { /* try to connect with exponential backoff */ for (int nsec = 1; nsec <= MAXSLEEP; nsec << 1) { if (connect(sockfd, addr, len) == 0) { /* connection accepted */ return 0; } /* delay before trying again */ if (nsec <= MAXSLEEP / 2) sleep(nsec); } return -1; }
#include <sys/socket.h> int listen(int sockfd, int backlog);
#include <sys/socket.h> int accept(int sockfd, struct sockaddr* addr, socklen_t* len);
#include <sys/socket.h> ssize_t send(int sockfd, const void* buf, size_t bytes, int flags); // 等同於 write,套接字必須已鏈接 ssize_t sendto(int sockfd, const void* buf, size_t bytes, int flags, const struct sockaddr* dstaddr, socklen_t dstlen);
#include <sys/socket.h> ssize_t recv(int sockfd, void* buf, size_t bytes, int flags); //相似於 read ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* addr, socklen_t* addrlen);
/* tcp_connect for client: * hostname or ip: www.google.com or 127.0.0.1 * service or port: http or 9877 */ int tcp_connect(const char* hostname, const char* service) { struct addrinfo hints; struct addrinfo* result; struct addrinfo* rp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int res = getaddrinfo(hostname, service, &hints, &result); if (res != 0) { fprintf(stderr, "tcp_connect error for %s, %s: %s", hostname, service, gai_strerror(res)); exit(0); } int sockfd; for (rp = result; rp != NULL; rp = rp->ai_next) { sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sockfd < 0) continue; int rc = connect(sockfd, rp->ai_addr, rp->ai_addrlen); if (rc == 0) break; close(sockfd); } if (rp == NULL) { unix_error("tcp_connect error"); } freeaddrinfo(result); return sockfd; }
/* tcp_listen for server: * hostname or ip: www.google.com or 127.0.0.1 * service or port: http or 9877 */ int tcp_listen(const char* hostname, const char* service, socklen_t* paddrlen) { struct addrinfo hints; struct addrinfo* result; struct addrinfo* rp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int res = getaddrinfo(hostname, service, &hints, &result); if (res != 0) { fprintf(stderr, "tcp_listen error for %s, %s: %s", hostname, service, gai_strerror(res)); exit(0); } int listenfd; for (rp = result; rp != NULL; rp = rp->ai_next) { listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (listenfd < 0) continue; int rc = bind(listenfd, rp->ai_addr, rp->ai_addrlen); if (rc == 0) break; Close(listenfd); } if (rp == NULL) { unix_error("tcp_listen error"); } Listen(listenfd, LISTENQ); if (paddrlen) { *paddrlen = rp->ai_addrlen; } freeaddrinfo(result); return listenfd; }
#include <sys/socket.h> int setsockopt(int sockfd, int level, int option, const void* val, socklen_t len); int getsockopt(int sockfd, int level, int option, void* val, socklen_t lenp);