什么是socket,iOS中的Socket如何实现

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
全栈老韩
全栈工程师,擅长iOS App开发、前端(vue、react、nuxt、小程序&Taro)开发、Flutter、React Native、后端(midwayjs、golang、express、koa)开发、docker容器、seo优化等。

Socket

网络以数据包的形式进行传播

高低电平

OSI网络模型:从7层模型,合并成4层模型

  • OSI的7层模型:
  1. 应用层
  2. 表示层
  3. 会话层
  4. 传输层
  5. 网络层
  6. 数据链路层
  7. 物理层

  • 4层模型
  1. 应用层
  2. 传输层 (tcp, udp)
  3. 网络互联层 (ip)
  4. 网络接口层

  • TCP
  1. 握手,建立传输数据的通道
  2. 可靠,数据大小不受限制,可以进行大数据传输
  3. 安全,可靠协议,安全送达
  4. 应用:数据下载

  • UDP
  1. 不可靠,只管发送,不确认对方是否收到
  2. 效率高,不需要建立连接
  3. 数据包大小受限制,大小限制在64k之内
  4. 应用:直播、游戏

socket

每一个端都有socket,通过ip地址进行连接,通过端口号进行通信。

过程:创建socket,建立连接,数据读取,关闭连接

Example

引入头文件

复制代码
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>

模拟本地socket:

复制代码
- (void)socketDemo {
    // 1. 创建socket
    /**
     domain:    协议域, AF_INET -> ipv4
     type:      socket类型,SOCK_STREAM
     protocol:  IPPROTO_TCP
     */
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    // 2. 连接服务器
    /**
    1 > 客户端socket
    2 > 服务器ip地址结构体的指针
    3 > 结构体数据的长度
    返回值:0表示成功
    */
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(12345);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
    
    int connResult = connect(clientSocket, (const struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (connResult == 0) { // Success
        NSLog(@"连接成功");
    } else { // fail
        NSLog(@"失败码 %d", connResult);
    }
    // 3. 发送数据
    /**
    1. 客户端socket
    2. 发送内容的地址
    3. 发送内容长度
    4. 发送方式标志,一般为0
    返回值:成功后发送的字节数,失效则返回SOCKET_ERROR
    */
    NSString *sendMsg = @"Hello";
    ssize_t sendLen = send(clientSocket, sendMsg.UTF8String, strlen(sendMsg.UTF8String), 0);
    NSLog(@"发送了 %ld 个字节", sendLen);
    
    // 4. 从服务器接收数据
    /**
    1. 客户端socket
    2. 接收内容的缓冲区地址
    3. 接收内容缓存区长度
    4. 接收方式,0表示阻塞,必须等待服务器返回数据
    返回值:如果成功,则返回读入的字节数,失效则返回SOCKET_ERROR
    */
    uint8_t buffer[1024]; // 准备空间
    ssize_t recvLen = recv(clientSocket, buffer, sizeof(buffer), 0);
    NSLog(@"接收了 %ld 个字节", recvLen);
    
    NSData *data = [NSData dataWithBytes:buffer length:recvLen];
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@", str);
    
    // 5. close
    close(clientSocket);
}

可以在terminal终端执行命令:nc -lk 端口号,始终监听本地计算机“端口号”的数据。Netcat是终端下用于调试和检查网络的工具包,可用于创建TCP/IP连接。

连接和发送/接收消息

复制代码
@property (nonatomic, assign) int clientSocket;
复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
//    [self socketDemo];
    
    [self doConnectionWithPort:80 addr:"61.135.169.121"];
//    [self sendMsg:@"我要奋斗!!"];
    NSString *request = @"GET / HTTP/1.1\n"
    "Host: www.baidu.com\n\n";
    [self sendMsg:request];
}

- (void)doConnectionWithPort:(int)port addr:(const char *)addr {
    _clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.s_addr = inet_addr(addr);
    
    
    int connResult = connect(_clientSocket, (const struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (connResult == 0) { // Success
        NSLog(@"连接成功");
    } else { // fail
        NSLog(@"失败码 %d", connResult);
    }
    
}

- (void)sendMsg:(NSString *)sendMsg {
    // 3. 发送数据
    ssize_t sendLen = send(_clientSocket, sendMsg.UTF8String, strlen(sendMsg.UTF8String), 0);
    NSLog(@"发送了 %ld 个字节", sendLen);
    
    
    // 4. 从服务器接收数据
    
    uint8_t buffer[1024]; // 准备空间
    ssize_t recvLen = recv(_clientSocket, buffer, sizeof(buffer), 0);
    NSLog(@"接收了 %ld 个字节", recvLen);
    
    NSData *data = [NSData dataWithBytes:buffer length:recvLen];
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@", str);
    
    
}

- (void)closeSocket {
    // 5. close
    close(_clientSocket);
}

网络

苹果的connection有一些地方做的不是很好,比如异步下载,数据回调不来,runloop默认不开启。
线程有任务才有可能不释放。

https协议:http + ssl (RSA加密)

https不会对客户端进行验证

RSA非对称加密
公钥,私钥 == 长度大概在200位的一串数字
明文公钥加密,私密解密
私钥加密,公钥解密!

对称加密
明文密钥加密 -> 密文
密文密钥解密 -> 明文

加盐

  1. 一个字符串,通过拼接
  2. 可以使用随机盐,一个客户端一个盐,保证安全
  3. 也可以再加上时间戳(服务器给的),来保证安全,服务器验证当前时间或者前1分钟内的数据,那么hacker就只有在2分钟之内进行破解,增加安全性

暂无评论,快来发表第一条评论吧