1、客户端-服务器模型
1)当一个客户端需要服务时,它向服务器发送一个请求,发起一个事务。
2)服务器收到请求后,解释它,并以适当的方式操作它的资源。
3)服务端给客户端发送一个响应,并等待下一个请求。
4)客户端收到响应并处理它。
2、网络
对于主机而言,网络只是一个I/O设备。
从物理上而言,网络是一个按地理远近组成的层次系统。
在互联网上,数据从一台主机传送到另一台主机需要八个步骤:
3、TCP/IP
TCP/IP实际上是一个协议族,其中每一个都提供了不同的功能。IP协议提供了基本的命名方法和传递机制,能够从一台主机想其他主机发送数据报。
IP机制是不可靠的。UDP协议稍微扩展了IP协议,包可以在进程间而不是主机间传送。TCP是一个构建在IP之上的复杂协议,提供了进程间可靠的全双工可靠连接。
IP地址:
一个IP就是一个32位无符号整数。IP地址通过DNS (Domain Name System) 数据库映射到域名
struct in_addr { unsigned int s_addr; /* Network byte order (big-endian) */ };
4、socket
从程序的角度来讲,套接字就是一个有相应描述符的打开的文件。一个套接字就是连接的一个端点,每个套接字都有套接字地址,它由一个Internet address 和 一个 16-bit integer port 。
客户端socket address 是由内核自动分配的,称为临时端口,服务器socket address 通常是某个知名的端口号,Unix上
文件/etc/services包含这台机器提供的服务和他们的知名端口号列表。
一个连接有他的两端的socket address 唯一确定
(cliaddr:cliport, servaddr:servport)
ios的socket:
iOS网络编程层次模型分为三层:
Cocoa层:NSURL,Bonjour,Game Kit,WebKit
Core Foundation层:基于 C 的 CFNetwork 和 CFNetServices
OS层:基于 C 的 BSD socket
- (void)loadDataFromServerWithURL:(NSURL *)url { NSString * host = [url host]; NSNumber * port = [url port]; // Create socket // int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0); if (-1 == socketFileDescriptor) { NSLog(@"Failed to create socket."); return; } // Get IP address from host // struct hostent * remoteHostEnt = gethostbyname([host UTF8String]); if (NULL == remoteHostEnt) { close(socketFileDescriptor); [self networkFailedWithErrorMessage:@"Unable to resolve the hostname of the warehouse server."]; return; } struct in_addr * remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0]; // Set the socket parameters // struct sockaddr_in socketParameters; socketParameters.sin_family = AF_INET; socketParameters.sin_addr = *remoteInAddr; socketParameters.sin_port = htons([port intValue]); // Connect the socket // int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters)); if (-1 == ret) { close(socketFileDescriptor); NSString * errorInfo = [NSString stringWithFormat:@" >> Failed to connect to %@:%@", host, port]; [self networkFailedWithErrorMessage:errorInfo]; return; } NSLog(@" >> Successfully connected to %@:%@", host, port); NSMutableData * data = [[NSMutableData alloc] init]; BOOL waitingForData = YES; // Continually receive data until we reach the end of the data // int maxCount = 5; // just for test. int i = 0; while (waitingForData && i < maxCount) { const char * buffer[1024]; int length = sizeof(buffer); // Read a buffer's amount of data from the socket; the number of bytes read is returned // int result = recv(socketFileDescriptor, &buffer, length, 0); if (result > 0) { [data appendBytes:buffer length:result]; } else { // if we didn't get any data, stop the receive loop // waitingForData = NO; } ++i; } // Close the socket // close(socketFileDescriptor); [self networkSucceedWithData:data]; }
5、The Sockets Interface
套接字接口是一组函数,它们和Unix I/O函数结合起来,用以创建网络应用。
因特网的套接字地址存放在类型为sockaddr_in的16字节结构中
/* Internet-style socket address structure */ struct sockaddr_in { unsigned short sin_family; /* Address family (always AF_INET) */ unsigned short sin_port; /* Port number in network byte order */ struct in_addr sin_addr; /* IP address in network byte order */ unsigned char sin_zero[8]; /* Pad to sizeof(struct sockaddr) */ };
socket函数:
客户端和服务器端用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
connect函数:
客户端通过调用connect函数建立和服务器的连接
#include <sys/socket.h> int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);//Returns: 0 if OK, −1 on error
connect函数会阻塞,直到连接成功或是发生错误,成功后,sockfd描述符就可以开始读写了。
bing函数:
#include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen); //Returns: 0 if OK, −1 on error
bind函数告诉内核my_addr中的服务器套接字地址和套接字描述符sockfd联系起来。
listen函数:
listen函数告诉内核,描述符是被服务器而不是客户端使用
#include <sys/socket.h> int listen(int sockfd, int backlog); Returns: 0 if OK, −1 on error
accept函数:
#include <sys/socket.h> int accept(int listenfd, struct sockaddr *addr, int *addrlen); //Returns: nonnegative connected descriptor if OK, −1 on error
accept函数等待来至客户端的连接请求到达侦听描述符listenfd,然后在addr中填写客户端的套接字地址,并返回一个已连接描述符,这个描述符用来和客户端通信。
listen函数返回的监听描述符是作为客户端请求的一个端点,它之被创建一次,并存在与服务器的整个声明周期,已连接描述符是客户端和服务器段之间已经建立起来的一个连接的端点,服务器每次接受请求shiite都会创建一次,它只存在于服务器为一个客户端服务的过程中。
6、web服务器
web客户端和服务器段交互用的是一个寄语文本的应用级协议,叫HTTP。
对于客户端和服务器而言,内容是一个MIME (Multipurpose Internet Mail Extensions) 类型相关的字节序列。
每条由web服务器返回的内容都是和它管理的某个文件相关联的,这些文件中的每一个都有一个唯一的名字叫
URL (Universal Resource Locator) ,例如:
http://www.google.com:80/index.html
表示主机www.google.com上的一个/index.html的文件,可执行文件的URL可以在文件名后偶棉包括程序参数。“?”字符分隔文件名和参数,而每个参数都用“&”字符分隔,例如:
http://bluefish.ics.cs.cmu.edu:8000/cgi-bin/adder?15000&213
标示了一个叫做/cgi-bin/adder的可执行文件,带两个参数15000和213.