网络编程就是编写程序使两台联网的计算机相互交换数据。socket编程也叫套接字编程。
UNIX/Linux 中的一切都是文件,为了表示和区分已经打开的文件,UNIX/Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)UNIX/Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。
网络连接也是一个文件,它也有文件描述符!
可以通过 socket() 函数来创建一个网络连接,或者说打开一个网络文件,socket() 的返回值就是文件描述符。有了文件描述符,我们就可以使用普通的文件操作函数来传输数据了。
- 用 read() 读取从远程计算机传来的数据;
- 用 write() 向远程计算机写入数据。
UNIX/Linux 不同的是,Windows 会区分 socket 和文件,Windows 就把 socket 当做一个网络连接来对待,因此需要调用专门针对 socket 而设计的数据传输函数,针对普通文件的输入输出函数就无效了。
Internet 套接字,根据传输协议,套接字可被分为UDP套接字 (UDP sockets) 和TCP套接字 (TCP sockets) 也叫 数据报式套接字(SOCK_DGRAM) 和 流格式套接字(SOCK_STREAM)
OSI 模型 (Open System Interconnection 的缩写,译为“开放式系统互联”)把网络通信的工作分为 7 层,从下到上分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。后简化为4层:接口层、网络层、传输层和应用层 , TCP/IP模型。TCP/IP 模型包含了 TCP、IP、UDP、Telnet、FTP、SMTP 等上百个互为关联的协议,其中 TCP 和 IP 是最常用的两种底层协议,所以把它们统称为“TCP/IP 协议族”。
基本代码 socket
socket(int af, int type, int protocol);
- af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6
- type 为数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字) 和 SOCK_DGRAM(数据报套接字/无连接的套接字)
- protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议
备注在linux下,socket函数返回int,在windows下则返回SOCKET类型句柄。
socket() 函数用来创建套接字,确定套接字的各种属性,然后服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来,只有这样,流经该 IP 地址和端口的数据才能交给套接字处理。类似地,客户端也要用 connect() 函数建立连接。
服务器端 int bind(int sock, struct sockaddr *addr, socklen_t addrlen); //Linux int bind(SOCKET sock, const struct sockaddr *addr, int addrlen); //Windows 客户端 int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen); //Linux int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen); //Windows
对于服务器端程序,使用 bind() 绑定套接字后,还需要使用 listen() 函数让套接字进入被动监听状态,再调用 accept() 函数,就可以随时响应客户端的请求了。
- int listen(int sock, int backlog); //Linux
- int listen(SOCKET sock, int backlog); //Windows
当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。
- int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); //Linux
- SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen); //Windows
备注:listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。
Linux 不区分套接字文件和普通文件,服务器端使用 write() 可以向套接字中写入数据,客户端使用 read() 可以从套接字中读取数据。
ssize_t write(int fd, const void *buf, size_t nbytes); ssize_t read(int fd, void *buf, size_t nbytes);
Windows 和 Linux 不同,Windows 区分普通文件和套接字,并定义了专门的接收recv() 函数和发送send() 函数
int send(SOCKET sock, const char *buf, int len, int flags); //服务器端 int recv(SOCKET sock, char *buf, int len, int flags); //客户端 TCP建立连接时要传输三个数据包,俗称三次握手(Three-way Handshaking)。可以形象的比喻为下面的对话: [Shake 1] 套接字A:“你好,套接字B,我这里有数据要传送给你,建立连接吧。” [Shake 2] 套接字B:“好的,我这边已准备就绪。” [Shake 3] 套接字A:“谢谢你受理我的请求。”
- SYN表示建立连接,
- FIN表示关闭连接,
- ACK表示响应,
- PSH表示有 DATA数据传输,
- RST表示连接重置。

文献参考:http://c.biancheng.net/view/2123.html