若是你点进了这个文章,我建议你直接访问 http://beej.us/guide/bgnet/ou... 学习socket编程,下面的资料是在读CSAPP时的一些总结,已通过时。html
从programmer的角度,咱们们能够把因特网当作一个世界范围内的主机集合,知足如下要求:数据库
主机集合被映射为一组32位的ip地址编程
这组ip地址被映射为一组称为因特网域名的标识符数组
主机上的进程可以经过链接和其余主机上的进程通讯服务器
ip地址是一个32位无符号整数,网络程序将ip地址存储在以下结构中:网络
#include <netinet/in.h> struct in_addr{ unsigned int s_addr; // big endian }
注意,tcp/ip为任意整数数据定义了统一的网络字节顺序:大端字节顺序。并提供了如下方法来在网络和主机间进行字节顺序的转换:app
#include <netinet/in.h> /* 32位/16位主机转网络 */ unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); /* 32位/16位网络转主机 */ unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort);
ip地址还可使用点分十进制表示法,因此系统提供了如下函数实现无符号整数和点分十进制表示方法的转换:dom
#include <arpa/inet.h> /* 点分表示->整数 * 若成功返回1,出错返回0 */ int inet_aton(const char *cp,struct in_addr *inp); /* 整数->点分表示 * 返回指向点分十进制字符串的指针 */ char *inet_ntoa(struct in_addr in);
因特网定义了域名集合和ip地址集合之间的映射,这个映射是经过分布在世界范围内的数据库来维护的。从概念上讲,DNS数据库由上百万以下所示的主机条目结构组成,其中每条定义了一组域名和一组ip地址之间的映射。socket
#include <netdb.h> struct hostent{ char *h_name; //主机的官方域名 char **h_aliases; //别名的字符串数组 int addrtype; //地址类型,通常是AF_INET int h_length; //地址的字节长度 char **h_addr_list; //字符串数组 }
网络程序经过调用下面的函数,从DNS数据库检索主机条目(for myself csapp 622)tcp
#include <netdb.h> /* 经过域名检索 * 若失败,返回NULL,并设置h_errno */ struct hostent *gethostbyname(const char *name); /* 经过ip地址检索,第二个参数为地址的字节长度 * 若失败返回NULL,并设置h_errno */ struct hostent *gethostbyaddr(const char *addr,int len,0);
一个套接字是链接的一个端点,每一个套接字都有相应的地址,是由一个因特网地址和一个16位的整数端口组成,通常用 “地址:端口”来表示。通常来讲,服务器的套接字端口一般是某个知名端口,而客户端端口由内核自动分配。
一个链接是由两端的套接字地址惟一肯定的。
套接字地址存放在以下所示的结构中:
#include <sys/socket.h> #include <netinet/in.h> /* 这个结构是为了函数 connect、bind、accept而设计的 */ struct sockaddr{ unsigned short sa_family; //protocol family char sa_data[14]; //address data } /* 套接字地址结构 */ struct sockaddr_in{ unsigned short sin_family; //address family 通常为AF_INET unsigned short sin_port; //大端表示的接口 struct in_addr sin_addr; //大端表示的ip地址 unsigned char sin_zero[8]; //pad to sizeof(struct sockaddr) }
客户端使用函数的顺序是 socket->connect
服务端使用函数的顺序是 socket->bind->listen->accept
#include <sys/types.h> #include <sys/socket.h> /* 建立套接字描述符,成功返回描述符,失败返回-1 * 通常老是这样使用:clientfd=socket(AF_INET,SOCK_STREAM,0); */ int socket(int domin,int type,int protocol);
socket返回的描述符还不能用于读写,在客户端和服务端要通过不一样的处理,如前文的顺序所示。
#include <sys/socket.h> /* 客户端使用该函数创建与服务器的链接 * 成功,返回0;失败,返回-1 */ int connect(int sockfd,struct sockaddr *serv_addr,int addrlen); /* 服务端使用该函数将服务器的地址和描述符链接起来 * addrlen是 sizeof(sockaddr_in) * 成功返回0,不然-1 */ int bind(int sockfd,struct sockaddr *my_addr,int addrlen); /* 服务端使用该函数将一个主动套接字改成监听套接字 * 成功返回0,失败-1 */ int listen(int sockfd,int backlog);