网络编程基础1
URL
url(统一资源定位符 Uniform Resourse Locator)
通过一个URl,能够找到互联网上唯一的一个1个资源
URL 就是资源的地址,位置,互联网上的每个资源都有一个唯一的URL
URL的基本格式 = 协议://主机地址/路径
http://www.baidu.com/ios/images/dong.jpg
http://202.108.22.5/img/bdlogo.gif
http协议的作用
http全称是Hypertext Transfer Protocol ,超文本传输协议
规定客户端和服务器之间的数据传输格式
让客户端和服务器能够进行有效的沟通
客户端发送请求到服务器请求需要遵循http 协议因为传输的数据是二进制的 ,客户端响应服务器的信息也是需要遵守协议的
下边我们来写一个小的程序来体验一下网络编程的乐趣
// 1. URL(确定要访问的网络资源页面,图片....路径)
// m 是 mobile 的缩写
NSURL *url = [NSURL URLWithString:@"http://m.baidu.com"];
//2.客户端向服务器发送request请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3. 建立网络连接,将请求(异步)发送给服务器
// 多线程的目的就是将耗时操作放在后台,所有的网络请求都是耗时的
// 几乎所有的网络请求,都应该是异步的
//下边的参数解释
1.请求
2.queue主队列 (对列的选择( 是否需要做耗时的操作))
不耗时的话可以用主队列,耗时的话用新建队列
3.完成时的回调block
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init]completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// 服务器响应已经结束!
//这句代码可以看出来我们的线程是一个异步线程
NSLog(@"%@", [NSThread currentThread]);
//输出二进制数据
NSLog(@"%@", data);
// 将二进制数据写入磁盘
[data writeToFile:@"/Users/apple/Desktop/123" atomically:YES];
//在当前的演练中,NSData 和 NSString 中保存的内容有什么区别?
// 没有区别!
// 所有的数据都是以二进制的形式保存在内存中的
// NSString 提供了字符串的展现形式,以及字符串的操作方法
// NSData 通常用于网络传输,以及写入文件
NSString *xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", xml);
}];
//这句可以判断当我们执行完的时候我们先执行主线程的操作
NSLog(@"come here");
//在上述中可以利用最后一句的 NSLog(@"come here"); 来判断是同步的还是异步的
给大家普及一下编码格式的
链接:字符编码格式
socket网络编程
网络三要素:
1.IP地址(唯一标示一个网络中的计算机,不允许重复)
2.端口号(电话号码类似IP号码:端口号类似于分机号码)
端口号
3.传输协议(通讯的规则TCP/UDP)
ipv4 0-255,0-255,0-255,0-255 2的32次方 = 42亿
ipv6 同上原理 128位 2的128次方
域名:ip地址的一个速记名称
在网络访问中本质都是通过ip地址进行访问的
DNS服务器进行域名的解析
计算机---->路由器----->DNS---->路由器再通过ip地址进行访问
DNS根服务器有504台大部分都在美国,根服务器记录世界全部的域名
本地回环地址:通过网卡访问本台机子
ip地址:通过路由器来访问本台机子
//我们可以用ping 127.0.0.1来看看书是不是我们的网卡坏了
传输协议概述
OSI网络模型
----> OSI网络模型
假设由A向B发送一个信息(只能在应用层对应用层进行信息的交流)
(A) 应用层 ->表示层 -> 会话层 -> 传输层 -> 网络层 ->数据链路 层 -> 物理层 (上述过程叫做封包 ) -------网线------(现在进行解包) (B)物理层 --> 数据链路层 --> 网络层 --> 传输层 ---> 会话层 --> 表示层 --> 应用层
路由器一般都在(网络层) 交换价在(数据链路层)
传输层对应的是socket(协议TCP/UDP)
TCP/IP的参考模型
1.应用层(应用层,表示层,会话层)
2.传输层(TCP/UDP协议)
3.网络互连层
4.网络接口层
TCP/UDP协议(传输层)
TCP与UDP的区别
TCP(传输控制协议):
1)提供IP环境下的数据可靠传输(一台计算机发出的字节流会无差错的发往网络上的其他计算机,而且计算机A接收数据包的时候,也会向计算机B回发数据包,这也会产生部分通信量),有效流控,全双工操作(数据在两个方向上能同时传递),多路复用服务,是面向连接,端到端的传输;
2)面向连接:正式通信前必须要与对方建立连接。事先为所发送的数据开辟出连接好的通道,然后再进行数据发送,像打电话。
3)TCP支持的应用协议:Telnet(远程登录)、FTP(文件传输协议)、SMTP(简单邮件传输协议)。TCP用于传输数据量大,可靠性要求高的应用。
UDP(用户数据报协议,User Data Protocol)
1)面向非连接的(正式通信前不必与对方建立连接,不管对方状态就直接发送,像短信,QQ),不能提供可靠性、流控、差错恢复功能。UDP用于一次只传送少量数据,可靠性要求低、传输经济等应用。
- UDP支持的应用协议:NFS(网络文件系统)、SNMP(简单网络管理系统)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。
3)大小限制在64K
总结:
TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。
socket(套接字层,插座)
参考:socket
Socket 就是为网络服务的一种机制
在Unix中,网络即是socket ,并不局限于TCP/UDP
Socket可以用于自定义协议
通信的两端都是Socket
网络通信其实就是socket之间的通信
数据在两个socket之间通过IO传输
Socket是纯C语言,跨平台
下边进入大家期待的socket编程开发(每个程序员都有一颗底层的心)
socket的五个步骤 socket--->connect----->write=====read----->read---->close
1.socket
domain: 协议域:AF_INET
type: Socket类型,SOCK_STREAM(流 TCP)/OCK_DGRAM(报文,提示:
在有些公司的程序员给服务器发送数据,会说:发送报文)
protocol: IPPROTO_TCP,提示:如果输入0,会根据第二个参数,自动选择协议
socket 如果>0 就是正确的
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
2.connect(连接到服务器(实际上就是一台计算机))
参数:1.客户端socket
2.指向数据结构sockaddr的指针,其中包括目的端口和IP地址
C 语言中没有对象,实现都是通过结构体来实现的
3. 结构体数据长度
struct sockaddr_in serverAddress;
// 1> 地址 inet_addr 可以将 ip 地址转换成整数
// 提示:在网络上的使用的很多数据,需要做字节翻转
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 2> 端口 htons 可以将端口转换成整数
// 端口号同样要做字节翻转
serverAddress.sin_port = htons(12345);
// 3> 协议
serverAddress.sin_family = AF_INET;
// 在 C 语言中,通常传递结构体的指针同时,会传递结构体的尺寸
int result = connect(clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress));
3.write(发送数据给服务器)
参数
1> 客户端socket
2> 发送内容地址
3> 发送内容长度
4> 发送方式标志,一般为0
返回值
如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR
提示:在很多C语言框架中,会将基本数据类型进行封装,使用的时候,便于后续框架的调整
*/
// 在 UTF8 编码中,一个中文对应 3 个字节
NSString *msg = @"约吗?";
ssize_t sendLen = send(clientSocket, msg.UTF8String,
strlen(msg.UTF8String), 0);
NSLog(@"%ld %tu %ld", sendLen, msg.length,
strlen(msg.UTF8String));
4. 从服务器接收数据
/**
参数
客户端socket
接收内容的空间
接收内容空间的长度
标记,如果是0,表示阻塞式,一直等到服务器的响应
返回值
接收到数据的长度
*/
// 定义一个空的数组,准备接收数据
uint8_t buffer[1024];
// 在 C 语言中,数组的名字,是指向数组第一个元素的指针
ssize_t recvLen = recv(clientSocket, buffer, sizeof(buffer), 0);
NSLog(@"接收到 %ld 字节", recvLen);
// 1> 取二进制数据
NSData *data = [NSData dataWithBytes:buffer length:recvLen];
// 2> 转换成字符串
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
5. 关闭连接
close(clientSocket);
在网络上发送的地址和我们实际的现实的不一样,是利用字节反转来做的
127.0.0.1
127对应的16进制为:0X7F
127.0.0.1对应的是:0X7F00001
然后再字节反转并转换10进制:16777343
终端下监听端口号码:12345 nc -lk 12345
我们可以封装一下,做成一个聊天系统
- (BOOL)connectToHost:(NSString *)host port:(int)port {
1. socket
self.clientSocket = socket(AF_INET, SOCK_STREAM, 0);
NSLog(@"%d", self.clientSocket);
2. 连接到另外一台计算机
struct sockaddr_in serverAddress;
1> 地址 inet_addr 可以将 ip 地址转换成整数
提示:在网络上的使用的很多数据,需要做字节翻转
serverAddress.sin_addr.s_addr = inet_addr(host.UTF8String);
2> 端口 htons 可以将端口转换成整数
端口号同样要做字节翻转
serverAddress.sin_port = htons(port);
3> 协议
serverAddress.sin_family = AF_INET;
在 C 语言中,通常传递结构体的指针同时,会传递结构体的尺寸
int result = connect(self.clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress));
return (result == 0);
}
- (NSString *)sendAndRecv:(NSString *)msg {
提示:在很多C语言框架中,会将基本数据类型进行封装,使用的时候,便于后续框架的调整
在 UTF8 编码中,一个中文对应 3 个字节
ssize_t sendLen = send(self.clientSocket,
msg.UTF8String, strlen(msg.UTF8String), 0);
NSLog(@"%ld %tu %ld", sendLen, msg.length,
strlen(msg.UTF8String));
uint8_t buffer[1024];
ssize_t recvLen = recv(self.clientSocket, buffer,
sizeof(buffer), 0);
NSLog(@"接收到 %ld 字节", recvLen);
取二进制数据
NSData *data = [NSData dataWithBytes:buffer length:recvLen];
转换成字符串
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return str;
}
- (void)disconnect {
// 5. 关闭连接
close(self.clientSocket);
}
//根据封装的东西来加载socket网站
--- 请求头 ---
1> 请求行
GET / HTTP/1.1
GET 表示从服务器"拿"数据
/ 访问服务器的根目录
HTTP/1.1 HTTP的协议以及版本
2> 请求头
Host: 要访问的主机
User-Agent: 用户代理,告诉服务器客户端的类型
Accept: 告诉服务器客户端支持的数据格式
Accept-Language: 告诉服务器客户端支持的语言
Accept-Encoding: 告诉服务器客户端支持的解压缩类型
HTTP请求本身的格式,是字符串格式的,最末一行,以 \n\n 结束,表示所有请求的内容发送完毕,服务器可以处理!
提示:key 值是 HTTP 协议定义的,不能随意更改!
--- 响应 ---
1> 状态行
HTTP/1.1 200 OK
HTTP/1.1 HTTP的协议以及版本
200 状态码(404)
2XX 成功
4XX 客户端错误
5XX 服务器错误
2> 响应头,服务器告诉客户端的一些信息
提示:响应的信息,通常在开发“下载”功能时,才会使用,平时用不着
Date: 响应日期
Server: 服务器的信息
// 文件长度
Content-Length: 24
3> 数据实体,从服务器返回的二进制数据!
//代码实现见下方
// http 端口是 80
if ([self connectToHost:@"127.0.0.1" port:80]) {
NSLog(@"连接成功");
}
// 发送消息给 web 服务器
// 建立请求字符串
NSString *request = @"GET /ios.m HTTP/1.1\n"
"Host: localhost\n"
"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:36.0) Gecko/20100101 Firefox/36.0\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n"
"Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3\n"
"Accept-Encoding: gzip, deflate\n\n";
NSLog(@"%@", [self sendAndRecv:request]);
//根据上述封装的函数来做socket编程加载百度页面
// http 端口是 80
if ([self connectToHost:@"61.135.169.125" port:80]) {
NSLog(@"连接成功");
}
// 发送消息给 web 服务器
// 建立请求字符串
NSString *request = @"GET / HTTP/1.1\n"
"Host: www.baidu.com\n"
"User-Agent: iPhone AppleWebKit\n\n";
// 对结果的处理
NSString *result = [self sendAndRecv:request];
// 找 \r\n 的出现的位置
NSRange range = [result rangeOfString:@"\r\n\r\n"];
// 判断是否找到
if (range.location == NSNotFound) {
NSLog(@"html 错误");
return;
}
NSString *html = [result substringFromIndex:range.location];
NSLog(@"%@", html);
[self.myWebView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.baidu.com"]];
智能家居
参考:智能家居
心跳包:(涉及到我们长连接和短连接问题)
总结:因为现在需要用到socket编程所以就临时学习了一下socket编程,socket编程是在我们的osi模拟模型的传输层,并且有TCP/UDP协议,从中学习到了tcp/udp的区别,从里边学到了socket编程的五个步骤都是跟C语言相关的函数,也学习到了socket如何封装,然后搭建自已的socket网站和聊天系统,了解了一些socket底层的实现原理