socket
Linux中的网络编程通过socket(套接字)实现。socket是一种文件描述符。
socket有三种类型:
(1)流式套接字(SOCK_STREAM)。流式套接字可以提供可靠的、面向连接的通讯流,它使用TCP协议。TCP协议保证了数据传输的正确性和顺序性。
(2)数据报套接字(SOCK_DGRAM)。数据报套接字提供了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错,它使用数据报协议UDP。
(3)原始套接字(SOCK_RAW)。原始套接字允许使用IP协议,主要用于新的网络协议的测试等。
网络地址
在socket程序设计中,struct sockaddr用于记录网络地址:
struct sockaddr
{
u_short sa_family;
char sa_data[14];
}
sa_family:协议族,采用"AF_***"形式,如:AF_INET(IP协议族)。
sa_data:14字节的特定协议地址。
在socket程序设计中,struct sockaddr_in同样用于记录网络地址。
struct sockaddr_in
{
short int sin_family; //协议族
unsigned short int sin_port; //端口号
struct in_addr sin_addr; //协议特定地址
unsigned char sin_zero[8]; //填0
}
编程中一般使用与sockaddr等价的sockaddr_in数据结构。
其中:
typedef struct in_addr
{
union{
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
}S_un_b;
struct{
unsigned short s_w1,
s_w2;
}S_un_w;
unsigned long S_addr; /*用一个32位整数记录IP地址*/
}S_un;
}IN_ADDR;
地址转换
IP地址通常由数字加点(192.168.0.1)的方式组成,而在struct in_addr中使用的IP地址是由32的整数表示的,为了转换我们可以使用下面两个函数:
int inet_aton(const char *cp,struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
函数中a代表ascii,n代表network。
inet_aton是将a.b.c.d形式的IP转化为32位的IP地址,存储在inp指针里面。inet_ntoa是将32位IP转换为a.b.c.d的格式。
网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。但是,如果发送主机是小端字节序的,这16位被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的,接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); /*把unsigned long类型从主机序转换到网络序 发送时使用*/ uint16_t htons(uint16_t hostshort); /*把unsigned short类型从主机序转换到网络序 发送时使用*/ uint32_t ntohl(uint32_t netlong); /*把unsigned long类型从网络序转换到主机序 接收时使用*/ uint16_t ntohs(uint16_t netshort); /*把unsigned short类型从网络序转换到主机序 接收时使用*/
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。
socket编程函数
进行socket编程常用函数有:
socket:创建一个socket。
bind:用于绑定IP地址和端口号到socket。
connect:该函数用于与服务器建立连接。
listen:设置服务器能处理的最大连接要求。
accept:用来等待来自客户端的socket连接请求。
send:发送数据。
recv:接收数据。