阅读 80

iOS开发轻松学习Socket

这两天很多学员都想听听关于 Socket 的内容! 所以花了一点时间就给它备了出来,公开课分享完全足够了!

这里通过文字形式纪录下来,方便大家对应学习

Socket是什么?

要了解什么是 Socket,首先需要了解 TCP/IP、UDP! ????

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。 UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

TCP/IP协议族包括运输层、网络层、链路层。现在你知道TCP/IP与UDP的关系了吧。

如果大家对于 七层协议模型 不是非常了解的话,你可以,沉下心来看看下面???????? 这张图:

那么TCP/IP、UDPsocket又有什么关系呢???

Socket应用层TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket怎么用

这里其实还有很多网络相关的知识需要科普,但是篇幅有限,如果靓仔靓女的你对于这一块有点陌生,你可以买一些网络相关的书籍

  • 《TCP/IP详解 卷1:协议》

  • 《图解HTTP》

  • 《Unix网络编程》

  • HTTPS权威指南

Socket 作为一套接口,那么是怎么用的呢? 下面一图胜前言: ????

Socket 传输的特点:

  • 1: 传输数据为字节级传输数据可自定义,数据量(对于手机应用讲:费用低)

  • 2: 传输数据时间短,性能高

  • 3: 适合于客户端和服务器端之间信息实时交互

  • 4: 可以加密,数据安全性强

正因为这些优势,常被用来做即时通讯重要媒介

上图就是通过 socket 在客户端和终端做的来回通讯

socket使用代码实现:

1: 创建socket

int socketID = socket(AF_INET, SOCK_STREAM, 0); self.clinenId= socketID; if (socketID == -1) {     NSLog(@"创建socket 失败");     return; } 复制代码

  • domain:协议域,又称协议族(family)。常用的协议族有AF_INETAF_INET6AF_LOCAL(或称AF_UNIXUnixSocket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

  • type:指定Socket类型。常用的socket类型有SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_PACKETSOCK_SEQPACKET等。流式SocketSOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。

  • protocol:指定协议。常用协议有IPPROTO_TCPIPPROTO_UDPIPPROTO_STCPIPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议STCP传输协议、TIPC传输协议。

注意:1.typeprotocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。

  • 返回值:如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKETLinux下失败返回-1

2: 建立连接

int result = connect(socketID, (const struct sockaddr *)&socketAddr, sizeof(socketAddr)); if (result != 0) {     NSLog(@"链接失败");     return; } NSLog(@"链接成功"); 复制代码

  • 参数一:套接字描述符

  • 参数二:指向数据结构sockaddr的指针,其中包括目的端口和IP地址

  • 参数三:参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得

  • 返回值: 成功则返回0,失败返回非0,错误码GetLastError()

struct sockaddr_in socketAddr; socketAddr.sin_family = AF_INET; socketAddr.sin_port   = SocketPort; struct in_addr socketIn_addr; socketIn_addr.s_addr  = SocketIP; socketAddr.sin_addr   = socketIn_addr; 复制代码

  • __uint8_t    sin_len;          假如没有这个成员,其所占的一个字节被并入到sin_family成员中

  • sa_family_t    sin_family;     一般来说AF_INET(地址族)PF_INET(协议族)

  • in_port_t    sin_port;         // 端口

  • struct    in_addr sin_addr;    // ip

  • char        sin_zero[8];       没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐

3: 发送消息

if (self.sendMsgContent_tf.text.length == 0) {     return; } const char *msg = self.sendMsgContent_tf.text.UTF8String; ssize_t sendLen = send(self.clinenId, msg, strlen(msg), 0); NSLog(@"发送 %ld 字节",sendLen); [self showMsg:self.sendMsgContent_tf.text msgType:0]; self.sendMsgContent_tf.text = @""; 复制代码

  • s:一个用于标识已连接套接口的描述字。

  • buf:包含待发送数据的缓冲区。

  • len:缓冲区中数据的长度。

  • flags:调用执行方式。

  • 返回值: 如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR.一个中文对应 3 个字节UTF8 编码!

4: 接受消息

while (1) {     uint8_t buffer[1024];     ssize_t recvLen = recv(self.clinenId, buffer, sizeof(buffer), 0);     if (recvLen == 0) {         NSLog(@"接收到了0个字节");         continue;     }     // buffer -> data -> string     NSData *data = [NSData dataWithBytes:buffer length:recvLen];     NSString *str= [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];     NSLog(@"%@---%@",[NSThread currentThread],str);     dispatch_async(dispatch_get_main_queue(), ^{         [self showMsg:str msgType:1];         self.sendMsgContent_tf.text = @"";     }); } 复制代码

  • 参数一: 客户端socket

  • 参数二: 接收内容缓冲区地址

  • 参数三: 接收内容缓存区长度

  • 参数四: 接收方式,0表示阻塞,必须等待服务器返回数据

  • 返回值:如果成功,则返回读入的字节数,失败则返回SOCKET_ERROR

Socket 总结

Socket 的使用还是非常简单的! 对于iOS开发有点吃力的原因是在于:

  • 都是C函数

  • 函数参数多并且陌生

  • 网络这一块知识的盲区


作者:Cooci
链接:https://juejin.cn/post/7018054170741571591

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐