一 点睛
Linux网络编程包括:用户态网络编程和内核态网络编程。
无论在Windows平台还是Linux平台,都对套接字实现了自己的一套编程接口。Windows下的Socket实现叫Windows Socket。Linux下的实现有两套:一套是伯克利套接口,起源于Berkeley Unix,这套接口很简单,得到了广泛应用,已经成为Linux网络编程事实上的标准;另一套是传输层接口,它是System V系统上网络编程API,所以这套编程接口更多是在Unix上使用。
Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用,以实现进程在网络中通信。
Socket编程接口其实就是用户进程(应用层)和传输层或网络层之间的编程接口。
二 网络程序架构
一种是B/S架构:浏览器查看网站上网页就是这种架构下的应用。
一种是C/S架构:例如,我们计算机上安装的QQ程序就是客户端,而在腾讯公司内部还有服务器端程序。
基于套接字的网络编程,通常使用C/S架构。一个简单的客户机和服务器之间的通信过程如下:
1 客户机向服务器提出一个请求。
2 服务器收到客户机的请求,进行分析处理。
3 服务器将处理的结果返回客户机。
三 套接字类型
Linux下有3种类型套接字
原始套接字与标准套接字(标准套接字包括流套接字和数据报套接字)的区别:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。
四 套接字地址结构
1 点睛
AF 表示ADDRESS FAMILY 地址族,PF 表示PROTOCOL FAMILY 协议族,但这两个宏定义是一样的,所以使用哪个都没有关系。
Winsock2.h中#define AF_INET 2,#define PF_INET AF_INET,所以在windows中AF_INET与PF_INET完全一样。
而在Unix/Linux系统中,在不同的版本中这两者有微小差别。
对于BSD,是AF。
对于POSIX是PF。
UNIX系统支持AF_INET,AF_UNIX,AF_NS等
而DOS,Windows中仅支持AF_INET,它是网际网区域。
不同协议族的套接字地址的含义是不同的,如AF_INET的地址为struct sockaddr_in,
而域套接字AF_INET的地址为struct sockaddr_un
2 sockaddr_in说明
sockaddr_in定义位置:/usr/include/netinet/in.h
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
__SOCKADDR_COMMON是一个宏,定义在/usr/include/bits/sockaddr.h
#define __SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family
\:续行符
##:连接前后两个参数
__SOCKADDR_COMMON (sin_);
宏展开后变为:
sa_family_t sin_family
sa_family_t定义于/usr/include/bits/sockaddr.h
typedef unsigned short int sa_family_t;
所以__SOCKADDR_COMMON (sin_);宏展开后的最终结果是:unsigned short int sin_family
五 主机字节序
1 点睛
小端字节序:数据的低字节存于内存低地址中,数据的高字节存于内存高字节中。
大端字节序:数据的低字节存于内存高地址中,数据的高字节存于内存低字节中。
2 测试主机的字节序
2.1 代码
#include
using namespace std;
int main(int argc, char *argv[])
{
int nNum = 0x12345678;
char *p = (char*)&nNum; //p指向存储nNum的内存的低地址
if (*p == 0x12) cout << "This machine is big endian." << endl; //判断低地址是否存放的是数据高位
else cout << "This machine is small endian." << endl;
return 0;
}
2.2 运行
[root@localhost test]# g++ -o test test.cpp
[root@localhost test]# ./test
This machine is small endian.
2.3 说明
这个机子是x86机子,x86机子基本都是小端模式。
六 网络字节序
1 点睛
网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型,操作系统无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用大端排序方式。
我们开发应用程序时,应该保证使用网络字节序,为此需要将数据由主机的字节序转换为网络字节序后再发出数据,接收方收到数据也要先转为主机字节序后再进行处理。
2 主机字节序和网络字节序相互转换的函数。
uint32_t htonl(uint32_t hostlong); //32位主机转网络
uint16_t htons(uint16_t hostshort); //16位主机转网络
uint32_t ntohl(uint32_t netlong); //32位网络转主机
uint16_t ntohs(uint16_t netshort); //16位网络转主机