这几天借了一本网络编程的经典书籍:《UNIX网络编程(卷一:套接字联网API)》,想着学习一下网络编程。下面的内容主要依靠这本书籍,然后,结合我自己的知识和网络资源,对Linux网络编程做由浅入深的学习。
我自己的理解是:套接字,即端点、端口,是建立在应用层和传输层之间的一个概念。
网络释义:套接字,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。为了区别不同的应用进程和连接,许多计算机操作系统为应用进程与TCP/IP协议交互提供了“套接字接口”,以便区分不同应用进程间的网络通信和连接。(3)原始套接字:SOCK_RAW;原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。
1、通用套接字地址结构:struct sockaddr
struct sockaddr
{
unsigned short sa_family;
char sa_data[14];
}
2、Internet下套接字地址结构:struct sockaddr_in
struct sockaddr_in
{
shortsin_family; //通信协议族,AF_INET、AF_UNIX
unsigned short sin_port;//通信端口
struct in_addrsin_addr;//IP地址
unsigned charsin_zero[8];
}
其中:
struct in_addr //32位IP地址
{
unsigned long s_addr;
}
struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。
3、地址转换函数
BSD网络软件中包含了两个函数,用来在二进制地址格式(网络字节序)和点分十进制字符串格式之间相互转换,但是这两个函数仅仅支持IPv4。
in_addr_t inet_addr(const char *cp);//返回32位二进制网络字节序的IPv4地址
int inet_aton(const char* strptr, struct in_addr *addrptr); //将strptr所指向的字符串转换成一个32位的网络字节序二进制值,并通过指针addrptr来存储
char * inet_ntoa(struct in_addr in);//返回指向一个点分十进制数串的指针,其中n表示32位网络字节序的IP地址,a表示点分十进制字符串
功能相似的两个函数同时支持IPv4和IPv6
const char * inet_ntop(int domain, const void *addr, char *str, socklen_t size);
int inet_pton(int domain, const char *str, void *addr);//将str所值的字符串转换成一个32位网络字节序二进制值,并通过指针addrptr来存储
例:
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8008);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
为了进行两者之间的转换,socket提供了转换的函数 有下面四个字节转换函数:
htons() :把unsigned short类型从主机序转换到网络序
htonl () :把unsigned long类型从主机序转换到网络序
ntohs() :把unsigned short类型从网络序转换到主机序
ntohl () :把unsigned long类型从网络序转换到主机序
另外,我们要知道,16位端口号(一个整形数字),32位IPv4地址(四个整形数字)。
通常的用法是:#define MYPORT 8008
int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
my_addr.sin_family = AF_INET; /* 主机字节序 */
my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */
bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
//memset(&my_addr.sin_zero, 0, 8);
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
端口:21
服务:FTP