网络编程
来源:互联网 发布:php正则获取a标签href 编辑:程序博客网 时间:2024/06/10 04:39
Network programming
网络无处不在,我们每天,都在和网络打交道,比如你打开浏览器去看一个网页,给别人发一个电子邮件, 这个时候,你就是在使用一个网络应用程序, 有趣的是,所有网络应用程序都是基于同样的网络模型,有着同样的逻辑结构,还有,依赖于同样的编程接口(programming interface).
网络应用程序要用用到很多其他的概念,进程, 信号, 对齐方式(byte ordering), 内存映射, 动态内存的分配在网络应用程序中都扮演了重要角色,当然,我们还会引入一些新的概念,我们需要去了解C(client) /S (server) 模型,还有 怎么去利用Internet 提供的服务去编写C/S 模型的程序。 最后,我们利用所有讲到概念去实现一个小型,但有点实际功能的web 服务器,这个服务器可以给真实的浏览器提供动态以及静态的文本、图形的支持。
Client-Server 编程模型
每个网络应用程序都是基于client-server 模型,这个模型的框架是指,一个网络应用程序包括一个server 进程 和一个(或者多个)client 进程, server 进程管理着一定的资源,通过对这些资源的管理 去给client 提供一些service. 举个例子,一个web 服务器管理着磁盘上的很多文件,它的职现就是接收client 的请求,还有帮client 执行一些计算。
一个FTP 服务器也是管理着磁盘上的文件,它的职现就是接收和存储来自client的请求。同样的道理,一个email 服务器负责为client端提供内容更新和阅读的功能。
client-server模型最基础的操作就是交互(transaction), 一个 client - server 交互包括四个步骤:
- 当client 需要服务的时候,它就向server 发送一个请求,这个请求就当是transaction的初始化,举个例子,当浏览器需要某个文件的时候,它就向Web 服务器发送一个请求。
- 当服务器接到这个请求,通过解析这个请求,然后去操作它所管理的一些资源,举个例子,当Web 服务器接到来自浏览器的请求后,它将会去读磁盘。
- server 发送一个相应给client. 然后等待下一次的请求。比如, Web server 将 client 需要的文件发送给client.
- client 接到了来自server的相应,然后去做一些动作。 比如, 当浏览器接到server 发来的文件后,它就把它在屏幕上显示出来。
这里需要注意的是,本文中说的client 和 server 指的是进程,而不是某台机器,也不是指host, 虽然在文章中会大量提到它,一个host 上面可以同时运行很多个不同的client 和server . client 和 server 的交互可以是同一台机器上的,也可以是不同机器上的。无论client和server 的映射关系是怎样的,client - server 模型是一致的。
Network
Client 和 server 通常运行在不同的 host 上面,这时候它就得用到computer network 提供的各种软,硬件资源。 Network 是一个非常复杂的系统, 在这里,我们仅仅把它比较表面的东西拿出来讨论,目标是从程序员的视角,列出一些概念。
对于一个host 来说,network 仅仅只是一些I/O 设备作为数据的源头或者存贮池(sink), 一块插在扩展槽上的网卡为网络提供了物理层的接口,从network上接收的数据,会经过网卡,I/O 还有内存总线最后传到内存里面去。比较典型的是通过 DMA 传输, 同理, 数据也可以通过网卡,从内存传到network上。
物理上说,一个network 是一个通过地理位置的远近关系来分层的结构,在最下面一层是 LAN (Local Area Network), 一般跨度是一个栋楼或者一个学校。目前为止,最流行的 LAN 技术是 Ethernet( 以太网), 这个是 上世纪70 年代中期开发出来的, Ethernet 已经被证明是非常具有弹性(resilient)的, 它的速度范围可以是 3Mb/b 到 10 Gb/s.
一个Ethernet segment 由一些网线加hub 组成。
The Global IP Internet
IP 地址
一个IP 地址是一个无符号的32位整数,网络应用程序是放在这样一个结构体里面。
/* Internet address structure */struct in_addr { unsigned int s_addr; /* Network byte order (big-endian) */};
#include <netinet/in.h>unsigned long int htonl(unsigned long int hostlong);unsigned short int htons(unsigned short int hostshort); Returns: value in network byte orderungigned long int ntohl(unsigned long int netlong);unsigned short int ntohs(unsigned short int netshort); Return:value in host byte order
sockets 编程
socket 接口(interface) 包括了很多个函数的组合,它配合Unix I/O 就可以去构建network 应用程序,目前市面上,大部分系统都有去实现socket, 包括 所有的类unix, windows, Macintosh , 下图是 socket 基本架构。
Socket 地址结构
从Unix kernel 的角度看,一个socket 就是一个连接(communication)的端点(end point). 从Unix 程序的角度看, 一个socket 就是一个已经打开的文件的文件描述符。
internet socket 地址是放在一个16 byte 长的结构体里面,
struct sockaddr {sa_family_tsa_family;/* address family, AF_xxx*/charsa_data[14];/* 14 bytes of protocol address*/};
IP 地址和port number 都是用 big endian 的方式的对齐
/* Structure describing an Internet (IP) socket address. */#define __SOCK_SIZE__16/* sizeof(struct sockaddr)*/struct sockaddr_in { sa_family_tsin_family;/* Address family*/ unsigned short intsin_port;/* Port number*/ struct in_addrsin_addr;/* Internet address*/ /* Pad to size of `struct sockaddr'. */ unsigned char__pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];};
socket 函数
client 和 server 用socket 来创建文件描述符。
#include <sys/types.h>#include <sys/socket.h>int socket(int domain, int type, int protocol); Returns: nonnegative descriptor if OK, -1 on error
在我们的代码里面, socket 始终带如下参数
/ * AF_INET 表明我们用的是Internet,
* SOCK_STREAM 表明socket 将作为internet 连接的一个端点
*/
clientfd = Socket(AF_INET, SOCK_STREAM, 0);
</pre><pre name="code" class="cpp">socket 返回的文件描述符仅仅只是一个打开的文件,我们还不能去read 和 write. 至于什么时候结束打开一个socket 取决于我们是server 还是 client.
后续章节将会讲到,如果一个client 如何结束打开一个socket.
</pre><h3>connect 函数</h3><div>client 和server 建立一个连接(connection) 是通过调用 connect 函数</div><div></div><div><pre name="code" class="cpp">#include <sys/socket.h>int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); Returns: 0 if OK, -1 on error
connect 函数直到连接成功建立或者发生error , 才会block. 如connect 返回0, 那么sockfd 描述符就可以被read 和 write.
最后,一个成功的连接由这样一个二元组表示
(x:y, serv_addr.sin_addr:serv_addr.sin_port)
其中 x 就是client 的ip 地址, y 是其临时(ephemeral)端口号,x 和 y 就唯一标识了client host 上的一个 process.
open_clientfd 函数
我们可以很容易的将socket 和 connect 函数,打包在一起,做成一个 open_clientfd ,用clientfd 去和server 建立一个连接。clientfd 将和这样一个server 建立连接,这个server 名字叫hostname, 还有,正在监听 well-known 的端口。clientfd 最终会返回一个socket 描述符。
int open_clientfd(char *hostname, int port){ int clientfd; struct hostent *hp; struct sockaddr_in serveraddr; if ((clientfd = sock(AF_INET, SOCK_STREAM, 0)) < 0) return -1; /* Check errno for cause of error */ /* Fill in the server's IP address and port */ if ((hp = gethostbyname(hostname)) == NULL) return -2; /* Check h_errno for cause of error */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveradd.sin_family = AF_INET; bcopy((char *)hp->h_addr_list[0], (char *)&serveraddr.sin_addr.s_addr, hp->h_length); serveraddr.sin_port = htons(port); /* Establish a connection with the server */ if (connect(clientfd, (SA *)&serveraddr, sizeof(serveraddr)) <0) return -1; return clientfd;}
bind 函数
剩下的几个socket 函数 bind, listen, accept 是给server 用的,用来和client 建立连接。
#include <sys/socket.h>int bind(int sockfd, struct sockaddr *my_addr, int addrlen); Returns: 0 if OK, -1 on error
bind 函数用来告诉kernel 去将myaddr 和sockfd 关联起来。
listen 函数
client 是发起连接的实体,server 是被动去接受连接,默认情况下,kernel 假设被socket 创建的描述符会一直存在直到连接断开,
by default, the kernel assumes that a descriptor created by the socket function corresponds to an active sock that will live on the client end of a connection.
server 调用listen 函数告诉kernel 这个descriptor 将会被server 用,而不是client.
#include <sys/socket.h>int listen(int sockfd, int backlog); Returns:0 if OK, -1 on error
1 0
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- 网络编程
- leetCode(34):Reverse Words in a String
- Android环境配置
- oracle临时表
- Struts2中namespace的用法
- 极简风格界面设计之初
- 网络编程
- js字符串常用判断方法
- UVa 11375 Matches
- [Html 5] WebStorage - localStorage和sessionStorage 基本使用方法
- leetcode解题报告232——Implement Queue using Stacks
- 重新开始Linux的学习
- nginx+php的配置
- hdu 1548 最短路||bfs
- 百度地图V3.5.0获取可视地图范围中心点、东北方、西南方(右上角、左下角)坐标