iOS Socket通信基础(一)

socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

Socket可以支持不同的传输层协议(TCP或UDP)是网络开发中不可或缺的一部分。

1、创建连接Socket(af,sockettype,protocol)

    //1 创建socket
    // 第一个参数 domain 协议族 指定IPV4
    // 第二个参数 type socket类型 流socket 数据报socket
    // 第三个参数 protocol 协议
    // 返回值 如果创建成功返回1
    int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

2、连接服务器Connect(sockid, destaddr, addrlen)

    //2 连接服务器
    // 第一个参数 socket描述符
    // 第二个参数 结构体 ip地址和端口
    // 第三个参数 结构体到长度 sizeof
    // 返回值 成功0
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    //htons用来转换端口号为大尾数据
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    int result = connect(clientSocket, (const struct sockaddr *)&addr, sizeof(addr));
    if (result != 0) {
        NSLog(@"失败");
        return ;
    }

3、向服务器发送数据send(sockid, buff, bufflen)

    //3 向服务器发送数据
    // 第一个参数 socket描述符
    // 第二个参数 发送到消息
    // 第三个参数 发送到字符个数
    // 第四个参数 是否阻塞
    const char * msg = "hello world";
    ssize_t sendCount = send(clientSocket, msg, strlen(msg), 0);
    NSLog(@"发送到字节数 %zd ",sendCount);

4、接收服务器返回到数据recv(sockid, buffer, sizeof(buffer), 0)

    //4 接收服务器返回到数据
    // 第一个参数 socket描述符
    // 第二个参数 接收数据的数组
    // 第三个参数 发送到字符大小
    // 第四个参数 是否阻塞
    uint8_t buffer[1024];

    NSMutableData *mData = [NSMutableData data];
    //首次返回数据
    ssize_t revCount = recv(clientSocket, buffer, sizeof(buffer), 0);
    [mData appendBytes:buffer length:revCount];
    //接收所有的数据
    while (revCount != 0) {
        revCount = recv(clientSocket, buffer, sizeof(buffer), 0);
        NSLog(@"接收的字节数:%zd",revCount);
        [mData appendBytes:buffer length:revCount];
    }

    //把字节数组转换为字符
    NSString *revMsg = [[NSString alloc]initWithData:mData encoding:NSUTF8StringEncoding];
    NSLog(@"接收到的消息:%@",revMsg);

5、关闭连接close(sockid)

    // 5 关闭连接
    close(clientSocket);

当让我们也可以把这些步骤进行封装整理,方便日后使用。

下面为一个请求百度的socket demo:
简单写了几个方法方便调用

#pragma mark - 连接服务器
- (BOOL)connectWithIp:(NSString *)ip port:(int)port
{
    //1 创建socket
    // 第一个参数 domain 协议族 指定IPV4
    // 第二个参数 type socket类型 流socket 数据报socket
    // 第三个参数 protocol 协议
    // 返回值 如果创建成功返回1
    int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    self.clientSocket = clientSocket;

    //2 连接服务器
    // 第一个参数 socket描述符
    // 第二个参数 结构体 ip地址和端口
    // 第三个参数 结构体到长度 sizeof
    // 返回值 成功0
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    //htons用来转换端口号为大尾数据
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.UTF8String);
    int result = connect(clientSocket, (const struct sockaddr *)&addr, sizeof(addr));
    if (result != 0) {
        NSLog(@"失败");
        return NO;
    }
    else{
        NSLog(@"成功");
        return YES;
    }
}

#pragma mark - 发送/接收数据
- (NSString *)sendAndRev:(NSString *)msg
{
    //3 向服务器发送数据
    // 第一个参数 socket描述符
    // 第二个参数 发送到消息
    // 第三个参数 发送到字符个数
    // 第四个参数 是否阻塞
    const char * tmsg = msg.UTF8String;
    ssize_t sendCount = send(self.clientSocket, tmsg ,strlen(tmsg), 0);
    NSLog(@"发送到字节数 %zd ",sendCount);

    //4 接收服务器返回到数据
    // 第一个参数 socket描述符
    // 第二个参数 接收数据的数组
    // 第三个参数 发送到字符大小
    // 第四个参数 是否阻塞
    uint8_t buffer[1024];

    NSMutableData *mData = [NSMutableData data];
    //首次返回数据
    ssize_t revCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);
    [mData appendBytes:buffer length:revCount];
    //接收所有的数据
    while (revCount != 0) {
        revCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);
        NSLog(@"接收的字节数:%zd",revCount);
        [mData appendBytes:buffer length:revCount];
    }

    //把字节数组转换为字符
    NSString *revMsg = [[NSString alloc]initWithData:mData encoding:NSUTF8StringEncoding];
    NSLog(@"接收到的消息:%@",revMsg);
    return revMsg;


}

#pragma mark - 关闭连接
- (void)closeConnect{
    // 5 关闭连接
    close(self.clientSocket);
}

设置请求:

//连接服务器
   BOOL isOK = [self connectWithIp:@"61.135.169.125" port:80];
   if (!isOK) {
        return;
    }
    NSString *request = @"GET / HTTP/1.1\r\n"
                          @"Host: www.baidu.com\r\n"
                          @"User-Agent: Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1\r\n"
                          @"Connection: close\r\n\r\n";
    NSString *response = [self sendAndRev:request];
    NSLog(@"响应头+内容=%@",response);

    //关闭连接
    close(self.clientSocket);

    if (response.length>0) {
        // 截取响应内容
        NSRange range = [response rangeOfString:@"\r\n\r\n"];
        NSString *html = [response substringFromIndex:range.length+range.location];
        NSLog(@"响应内容=%@",html);
    }

设置请求头时需要注意头部的参数格式
1、键-值间有空格隔开,每个参数独占一行,以’\r\n’进行换行
2、最后一个参数以’\r\n\r\n’进行结尾
3、User-Agent不要放在最后一个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值