网络通讯三要素
1.IP地址(主机名)
网络中设备的标示
不易记忆,可以用主机名
本地回环地址:127.0.0.1主机名:localhost
每台计算机都有一个127.0.0.1
如果 127.0.0.1ping不通,说明网卡不工作
如果本机地址ping不通,说明网线坏了
2.端口号
用于标示进程的逻辑地址,不同进程的标示
有效端口:0~65535
其中0~1024由系统使用或者保留端口
开发中不要使用1024以下的端口
3.传输协议
TCP(传输控制协议)
UDP(数据报文协议)
通过IP找机器,通过端口找程序,通过协议确定如何传输数据
常见网络协议
协议 端口 说明
HTTP 80 超文本传输协议
HTTPS 443 HTTP+SSL,HTTP的安全版
FTP 20/21/990 文件传输协议
POP 110 邮局协议
SMTP 25 简单邮件传输协议
telnet 23 远程终端协议
SSH 22 Secure Shell
TCP & UDP
UDP(用户数据报协议)
只管发送,不确认对方是否接收到
将数据源和目的封装成数据包中,不需要建立连接
每个数据报的大小限制在64K之内
因为无需连接,因此是不可靠协议
不需要建立连接,速度快
应用场景:多媒体教室/网络流媒体
TCP(传输控制协议)
建立连接,形成传输数据的通道
在连接中进行大数据传输(数据大小不受限制)
通过三次握手完成连接,是可靠协议,安全送达
必须建立连接,效率会稍低
Socket(套接字层、插座)
Socket就是为网络服务提供的一种机制
通信的两端都是Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过I/O传输
Socket是纯C语言的,是跨平台的
长/短连接 & 心跳包
短连接
数据请求结束后,立即断开连接
能够及时释放服务器资源
让服务器能够为更多的用户提供服务
长连接
一旦连接建立之后,始终保持连接状态
后续只需发送和接收数据即可,数据响应更及时
长连接对服务器资源占用比较大
对交互响应要求快的应用,例如即时通讯,需要使用长连接
心跳包
是检测长连接的重要技术手段
可以由服务器发送,定时向客户端发送小数据,根据回执判断客户端是否在线
也可以由客户端发送,定时向服务器发送小数据,报告客户端当前在线
Socket 加载百度
修改接收函数
- (NSString*)sendAndRecv:(NSString*)msg {
// 1. 发送
ssize_t sendLen = send(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String),0);
NSLog(@"发送 %ld %tu %ld", sendLen, msg.length, strlen(msg.UTF8String));
// 2. 接收
uint8_t buffer[1024];
NSMutableData *dataM = [NSMutableData data];
ssize_t recvLen = -1;while(recvLen !=0) {
recvLen = recv(self.clientSocket, buffer,sizeof(buffer),0);
[dataM appendBytes:buffer length:recvLen];
}
NSString*result = [[NSStringalloc] initWithData:dataM encoding:NSUTF8StringEncoding];
// 3. 断开连接
[selfdisconnect];
returnresult;
}
发送请求
- (void)viewDidLoad {
[superviewDidLoad];
if(![selfconnectToHost:@"61.135.185.17"port:80])
{NSLog(@"连接失败");return;
}
// 发送请求
NSString*request =@"GET / HTTP/1.1\r\n""Host: m.baidu.com\r\n""User-Agent: iPhone AppleWebKit\r\n""Connection: Close\r\n\r\n";
NSString*resposne = [selfsendAndRecv:request];
// 获取
htmlNSRangerange = [resposne rangeOfString:@"\r\n\r\n"];
if(range.location!=NSNotFound) {
NSString*html = [resposne substringFromIndex:range.location+ range.length]; [self.webViewloadHTMLString:html baseURL:[NSURLURLWithString:@"http://m.baidu.com"]];
}else{
NSLog(@"加载失败");
}
}
Socket 聊天
搭建界面
自动布局 & 代码连线
/// 主机地址
@property(weak,nonatomic)IBOutletUITextField *hostName;
/// 端口号
@property(weak,nonatomic)IBOutletUITextField *portNumber;
/// 发送消息文字
@property(weak,nonatomic)IBOutletUITextField *messageText;
/// 接收文字标签
@property(weak,nonatomic)IBOutletUILabel*recvLabel;
/// 发送按钮
@property(weak,nonatomic)IBOutletUIButton*sendButton;
调整连接到主机代码,添加参数
/// 连接
- (BOOL)connectToHost:(NSString*)hostName port:(int)port {
// 1. socket
self.clientSocket= socket(AF_INET, SOCK_STREAM,0);
NSLog(@"%d",self.clientSocket);
// 2. 连接
structsockaddr_in serverAddr;
serverAddr.sin_family= AF_INET;
serverAddr.sin_addr.s_addr= inet_addr(hostName.UTF8String); serverAddr.sin_port= htons(port);
return connect(self.clientSocket, (conststructsockaddr *)&serverAddr,sizeof(serverAddr)) ==0;
}
实现连接功能
- (IBAction)connect {BOOLresult = [selfconnectToHost:self.hostName.textport:self.portNumber.text.intValue];
self.sendButton.enabled= result;self.recvLabel.text= result ?@"成功":@"失败";
}
调整发送和接收方法,添加参数
/// 发送和接收
- (NSString*)sendAndRecv:(NSString*)msg {
// 1. 发送
ssize_t sendLen = send(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String),0);
NSLog(@"发送 %ld %tu %ld", sendLen, msg.length, strlen(msg.UTF8String));
// 2. 接收
uint8_t buffer[1024];
ssize_t recvLen = recv(self.clientSocket, buffer,sizeof(buffer),0);
NSLog(@"接收了 %ld %ld", recvLen,sizeof(buffer));
NSString*result = [[NSStringalloc] initWithBytes:buffer length:recvLen encoding:NSUTF8StringEncoding];
returnresult;
}
发送和接收操作
- (IBAction)send {
self.recvLabel.text= [selfsendAndRecv:self.messageText.text];
}