iOS原生Socket编程

本文详细介绍了如何在iOS中进行原生Socket编程,包括客户端和服务器端的实现步骤。从创建socket、连接服务器、接收与发送信息,到服务器的监听和处理客户端连接,每个环节都有清晰的代码示例。最后展示了模拟器运行效果,并提供了GitHub上的完整demo链接,供读者实践和学习。
摘要由CSDN通过智能技术生成

iOS原生Socket编程

一、Socket连接原理
  • 1、原理流程图
    在这里插入图片描述
二、客户端编程代码
  • 1、初始化准备数据
//引入头文件
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
//htons将一个无符号整型数据转为网络字节顺序,不同cpu是不同的顺序
#define SOCKET_PORT htons(8040)
//ip地址:以本地为例子
#define IP_ADRR "127.0.0.1"
  • 2、创建soket
//创建socket
/// int socket(int family, int type, int protocol);
///参数一:family:协议簇或者协议域(AF_INET:IPv4协议;AF_INET6:IPv6协议;AF_LOCAL:Unix域协议;AF_ROUTE:路由套接字;AF_KEY:密钥套接字)
///参数二:type:套接字类型(SOCK_STREAM:字节流套接字;SOCK_DGRAM:数据包套接字;SOCK_EQPACKET:有序分组套接字;SOCK_RAW:原始套接字)
///参数三:protocol协议类型(IPPROTO_TCP:TCP传输协议;IPPROTO_UDP:UDP传输协议;IPPROTO_SCTP:SCTP传输协议;0:选择所给定family和type组合的系统默认值)
int socketId = socket(AF_INET, SOCK_STREAM, 0);
self.clientId = socketId;
if (socketId == -1) {
        NSLog(@"create socket fail");
        return;
}
  • 3、socket连接
//连接socket
struct sockaddr_in socketAdrr;
socketAdrr.sin_family = AF_INET;
socketAdrr.sin_port = SOCKET_PORT;
struct in_addr socketIn_adrr;
socketIn_adrr.s_addr = inet_addr(IP_ADRR);
socketAdrr.sin_addr = socketIn_adrr;
///int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen)
///参数一:sockfd(socket描述符)
///参数二:servaddr(socket地址结构体指针)
///参数三:addrlen(socket地址结构体大小)
int result = connect(socketId, (const struct sockaddr *)&socketAdrr, sizeof(socketAdrr));
if(result != 0){
        NSLog(@"客户端:连接失败");
        return;
}
  • 4、接受信息
///异步接受信息,防止阻塞主线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self recvMsg];
});
- (void)recvMsg{
        while (1) {
            uint8_t buffers[1024];
            ///ssize_t recv(int, void *, size_t, int)
            ///参数一:socket标志符
            ///参数二:缓冲区
            ///参数三:缓冲区大小
            ///参数四:指定调用方式,一般设置为0
            ssize_t sizeLen = recv(self.clientId, buffers, sizeof(buffers), 0);
            NSLog(@"客户端:接收到%zd个字节",sizeLen);
            if(sizeLen == 0){
                continue;
            }
            NSData *data = [NSData dataWithBytes:buffers length:sizeLen];
            NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"客户端:%@ 接收到消息:%@",[NSThread currentThread],msg);
        }
}
  • 5、发送消息
- (void)sendMsg:(NSString *)msg{
        if(msg.length <= 0) return;
        const void *buff = msg.UTF8String;
        ///ssize_t     write(int __fd, const void * __buf, size_t __nbyte)
        ///参数一:socket标志符
        ///参数二:缓冲区
        ///参数三:缓冲区大小
        ssize_t sizeLen = write(self.clientId, buff, strlen(buff));
        NSLog(@"客户端:发送%zd字节消息",sizeLen);
}
三、本地制作服务器编程(测试)
  • 1、创建socket
 //创建socket
/// int socket(int family, int type, int protocol);
///参数一:family:协议簇或者协议域(AF_INET:IPv4协议;AF_INET6:IPv6协议;AF_LOCAL:Unix域协议;AF_ROUTE:路由套接字;AF_KEY:密钥套接字)
///参数二:type:套接字类型(SOCK_STREAM:字节流套接字;SOCK_DGRAM:数据包套接字;SOCK_EQPACKET:有序分组套接字;SOCK_RAW:原始套接字)
///参数三:protocol协议类型(IPPROTO_TCP:TCP传输协议;IPPROTO_UDP:UDP传输协议;IPPROTO_SCTP:SCTP传输协议;0:选择所给定family和type组合的系统默认值)
self.serverId = socket(AF_INET, SOCK_STREAM, 0);
if(self.serverId == -1){
        NSLog(@"服务端:服务端创建socket失败");
        return;
}
  • 2、绑定socket
//绑定socket
struct sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(8040);
struct in_addr inAddr;
inAddr.s_addr = inet_addr("127.0.0.1");
sockAddr.sin_addr = inAddr;
bzero(&sockAddr.sin_zero, 8);
///int     bind(int, const struct sockaddr *, socklen_t)
///参数一:socket描述符
///参数二:socket地址结构体指针
///参数三:socket地址结构体大小
int bindResult = bind(self.serverId, (const struct sockaddr *)&sockAddr, sizeof(sockAddr));
if(bindResult == -1){
        NSLog(@"服务端:socket 绑定失败");
        return;
}
  • 3、监听socket
//监听socket
///int  listen(int, int)
///参数一:socket标识符
///参数二:最大连接数
int lisentResult = listen(self.serverId, kMaxConnectCount);
if(lisentResult == -1){
        NSLog(@"服务端:监听失败");
        return;
}
  • 4、接收消息
///接受信息
dispatch_async(dispatch_get_global_queue(0, 0), ^{
        struct sockaddr_in client_address;
        socklen_t socklen;
        ///int     accept(int, struct sockaddr * __restrict, socklen_t * __restrict)
        ///参数一:socket描述符
        ///参数二:socket地址结构体指针
        ///参数三:socket地址结构体大小
        int client_socket = accept(self.serverId, (struct sockaddr *)&client_address, &socklen);
        self.clientSocket = client_socket;
        if(client_socket == -1){
            NSLog(@"服务端:接受客户端连接错误");
        }else{
            NSString *acceptInfo = [NSString stringWithFormat:@"客户端 in,socket:%d",client_socket];
            NSLog(@"服务端:%@",acceptInfo);
            [self recvMsg:client_socket];
        }
});
///接受信息
- (void)recvMsg:(int)clientSocket{
        while (1) {
            char buff[1024] = {0};
            ssize_t sizeLen = recv(clientSocket, buff, 1024, 0);
            if(sizeLen>0){
                NSLog(@"服务端:客户端来消息了");
                NSData *recvData  = [NSData dataWithBytes:buff length:sizeLen];
                NSString *recvStr = [[NSString alloc] initWithData:recvData encoding:NSUTF8StringEncoding];
                NSLog(@"服务端:%@",recvStr);
            }else if (sizeLen == -1){
                NSLog(@"服务端:读取数据失败");
                break;
            }else if (sizeLen == 0){
                NSLog(@"服务端:客户端走了");
                close(clientSocket);
                break;
            }
        }
}
  • 5、发送消息
///发送信息
- (void)sendMsg:(NSString *)msg{
        size_t sendResult = write(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String));
        NSLog(@"服务端:发送%zu字节数据",sendResult);
}
  • 6、关闭连接
///关闭连接
- (void)close:(int)clientSocket{
        int closeResult = close(clientSocket);
        if(closeResult == -1){
            NSLog(@"服务端:关闭失败");
            return;
        }else{
            NSLog(@"服务端:关闭成功");
        }
}
四、操作步骤
  • 1、效果图
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHsBqW7g-1616670886334)(media/16158744312890/16166650480766.jpg)]

  • 2、模拟器运行->点击服务端开始socket->点击客户端连接socket,连接成功后即可开始通信


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值