socket

作者: nothing_c | 来源:发表于2016-10-31 22:33 被阅读54次

    7层: 应用层, 表示层,会话层, 传输层, 网络层(协议), 数据链路层(联网),物理层(硬件)

    socket是传输层 : http是处于应用层

    用OC里的C写的 双向 即时

    //网络字节序指的是大端模式

    //大端高位在低地址,低位在高地址

    //小端高位在高地址,低位在低地址

    //字节序

    //导入需要的系统头文件

    #import

    #import

    #import

    #import

    #import

    //配置文件

    #import"LPSocket.h"

    //*

    1.创建socket对象

    1.1创建CFSocketContext对象

    1.2 实现socket对象初始化中的TCPServerConnectCallBack的回调方法

    1.2.1判断回调是否成功

    1.2.2创建self对象 开辟分线程,实现线程方法

    1.2.3self对象调用登录方法

    1.3判断socket对象是否创建成功

    1.4配置socket的地址信息

    1.4.1设置地址

    1.4.2设置消息循环

    1.4.3将消息源添加到消息循环中

    1.4.3对于创建的对象进行释放

    2.解析终端登录包

    2.1计算字节长度

    2.2除去长度的字节长度

    2.3设置标志,命令号

    2.4发送请求

    3.解析心跳包

    3.1解析读取心跳包的数据

    3.2再解析 发送请求

    - (void)viewDidLoad {

    [super viewDidLoad];

    [self connectToServer];

    }

    //打开socket连接,长连接双向的

    - (void) connectToServer {

    //self一个任意指针的数据,可以用在创建CFSocket对象时相关联。这个指针被传递给所有的上下文中定义的回调。

    //创建一个结构体

    //在MRC环境下的开发

    CFSocketContext CTX = {0,self,NULL,NULL,NULL};

    //kCFAllocatorDefault一都使用默认的

    //PF_INET使用ipv4 :  PF_INET6使用ipv6

    //TCPServerConnectCallBack回调的方法名需要实现回调方法点两下

    //kCFSocketConnectCallBack指定当连接到服务器的时候回调

    // &CTX提前设置的结构体

    _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketConnectCallBack, TCPServerConnectCallBack, &CTX);

    //判断对象是否创建成功

    if(NULL==_socket){

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"创建套接字失败" delegate:nil cancelButtonTitle:@"关闭" otherButtonTitles:nil];

    [alert show];

    [alert release];

    return;

    }

    //sockaddr_in配置socket的地址信息

    structsockaddr_inaddr4;

    //初始化addr4的内存

    //mem == memory内存

    //sizeof(addr4)计算addr4在内存中占用空间(几个字节)

    memset(&addr4, 0,sizeof(addr4));

    //让内存对齐按一个字节对齐防止出现片段编码

    bzero(&addr4,sizeof(addr4));

    //赋值一下结构体本身的长度

    addr4.sin_len = sizeof(addr4);

    //AF_INET  ipv4

    addr4.sin_family = AF_INET;

    //将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)

    addr4.sin_port = htons(SOCKET_PORT);

    //将一个点分十进制的IP转换成一个长整数型数INET_ADDR()。

    //[SOCKET_IP UTF8String] OC字符串转C字符串

    addr4.sin_addr.s_addr = inet_addr([SOCKET_IPUTF8String]);

    //把sockaddr_in结构体中的地址转换为Data,CFDataRef == NSData

    CFDataRefaddress = CFDataCreate(kCFAllocatorDefault, (UInt8*)&addr4,sizeof(addr4));

    // address CFDataRef类型的包含上面socket的远程地址的对象

    CFSocketConnectToAddress(_socket, address, 30);

    //获取当前线程的消息循环

    CFRunLoopRefcfrl = CFRunLoopGetCurrent();

    //创建一个消息源

    CFRunLoopSourceRefsource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0);

    //把消息源添加到消息循环中

    CFRunLoopAddSource(cfrl, source,kCFRunLoopCommonModes);

    //CFXXXXXRef创建的对象需要释放

    CFRelease(source);

    CFRelease(address);

    }

    //static类似于OC的加号方法copy过来进行修改

    staticvoidTCPServerConnectCallBack(CFSocketRefsocket,CFSocketCallBackTypetype,CFDataRefaddress,constvoid*error,void*info){

    NSLog(@"连接到socket服务器");

    //当socket为kCFSocketConnectCallBack时,失败时回调会返回一个错误代码指针(data),其他情况返回NULL

    if(error != NULL){

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"连接失败" delegate:nil cancelButtonTitle:@"关闭" otherButtonTitles:nil];

    [alert show];

    [alert release];

    return;

    }

    //因为self调用不了-号方法所以就创建一个self的对象

    //info和CFSocketContext CTX = {0,self,NULL,NULL,NULL};中的self对应

    ZYViewController *infoObject = (ZYViewController *)info;

    //其效果与NSThread的detachNewThreadSelector:toTarget:withObject:是一样的。

    //开启一个分线程,调用readStream这个方法,这个方法是在分线程中进行的。

    [info ObjectperformSelectorInBackground:@selector(readStream) withObject:nil];

    [info ObjectuserLogin];

    //测试用的

    //[info Object httpTest];

    }

    - (void)httpTest {

    NSString *str =@"GET /SocketHttpTest/TestServlet?name=wwwwww&password=12dddssd HTTP/1.1\r\n"

    @"Host:localhost\r\n"

    @"connection:close\r\n\r\n"

    @"\r\n";

    constchar *s2 = [strUTF8String];

    send(CFSocketGetNative(_socket),s2,[strlength], 0);

    }

    //解析终端登录包

    - (void)userLogin {

    //网络字节序,大端模式

    //一共需要23个字节(包含长度本身2个)

    chardata[23];

    data[0] = (21 >> 8) & 0x000000ff;//0

    data[1] = 21 & 0x000000ff;//21

    //使用配置文件宏定义好的内容

    data[2] =CLIENT_SIDE;

    data[3] =LOGIN_COMMAND;

    //软件版本全为0测试

    for(inti = 4; i < 12; i++) {

    data[i] = 0;

    }

    //设备序列号测试

    for(inti = 12; i < 23; i++) {

    data[i] = 't';

    }

    //发送请求

    send(CFSocketGetNative(_socket),&data,sizeof(data), 0);

    }

    - (void)readStream {

    //将来里面放的是‘包长度(2)、哪个端(1)、命令号(1)’4个

    charheader[4];

    //一直读取服务器返回的包

    //recv方法参数1.从哪个连接中读,2.读到的数据存到内存中的地址,3.读多长的数据

    while(recv(CFSocketGetNative(_socket),&header,sizeof(header), 0)) {

    //哪个端第三个

    Byteside = header[2];

    //命令号第四个

    Bytecommand = header[3];

    if(command == LOGIN_RESPONSE_COMMAND&& side == 'S') {

    NSLog(@"登陆返回了");

    //得到包的长度(除去长度字段本身)或运算(转换为十进制结果)

    intlength = ( header[0] << 8 ) | header[1];

    //这个字节数组放的是‘当前时间、结果代码、原因’

    charloginResponse[length - 2];

    //除去前四个字节后继续解析读取

    if(recv(CFSocketGetNative(_socket),&loginResponse,sizeof(loginResponse), 0)) {

    NSLog(@"年____  %d",loginResponse[0]);

    NSLog(@"月____  %d",loginResponse[1]);

    NSLog(@"日____  %d",loginResponse[2]);

    NSLog(@"时____  %d",loginResponse[3]);

    NSLog(@"分____  %d",loginResponse[4]);

    NSLog(@"秒____  %d",loginResponse[5]);

    BOOLfailed = loginResponse[6];

    NSLog(@"登陆是否失败%d",failed);

    }

    } else if(command == 0x80 && side == 'S') {

    NSLog(@"收到心跳包");

    //if外边已经读取过4个了,只用读取剩下的两个

    charinterval[2];

    if(recv(CFSocketGetNative(_socket),&interval,sizeof(interval), 0)) {

    //心跳时间是多字节往左移8位

    int nextInterVal = (interval[0] << 8) | interval[1];

    NSLog(@"下次心跳时间%d",nextInterVal);

    chardata[4];

    //2-->0000 0010考虑大端模式高低位互换0--0 1--2

    data[0] = 0;

    data[1] = 2;

    data[2] = 'E';

    data[3] = 0x00;

    //发送数据

    send(CFSocketGetNative(_socket),&data,4, 0);

    }

    }

    }

    }

    @end

    相关文章

      网友评论

          本文标题:socket

          本文链接:https://www.haomeiwen.com/subject/hsnputtx.html