TCP, UDP, Socket. 基础篇

 


了解  IP 协议是网络层的, TCP, UDP是传输层的, socket是回话层的.

TCP与DUP 的区别

 TCP: 是传输控制协议,通过三次握手完成连接,数据大小不限制

 UDP: 用户数据报协议,不需要建立连接,每一数据报大小在64K之内,不可靠

所以 TCP 多用与像访问网站, 等需要服务端, 用户端,两方配合的应用.  而UDP 通常用户像多媒体共享这样的, 只管把数据发出去,具体个人有没有在, 有没有卡, 对共享发布者不影响.


第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
  第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
  如果看不太懂 上面的 就简单理解为  客户端对服务端说: 我要给你发消息.  服务器受到消息回复说: 行你发吧   客户端受到消息回复服务端说: 那我发了, 你那边准备好. 


TCP 与HTTP 的关系

 TCP协议:  网络传递信息管理的一些规范,可以理解为 计算机之间统一使用的传输规范, (理解为:规定两个人直接交流的方式口头交流, 书面交流.)

 HTTP:超文本传输协议协议 是基于 TCP,确定交流的语言用汉语还是用英语.

总的来说, TCP确定的是传输的方式, 二 HTTP 是在传输方式的基础上, 确定数据传输的格式. 


socket 和 HTTP 的关系 

Socket : 网络通信的实质就是 socket之间的通信, HTTP协议的传输实质就是socket的传输.   

HTTP: 连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接, 所以HTTP是短链接

socket: 理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去, 所以socket是长连接. 


实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。

 Socket: 分为流式Socket:针对面向连接的TCP服务应用,数据报式Socket:面向无连接的UDP服务应用.

使用Socket  可以只传输数据本身,而不用进行XML封装.




实例代码  使用的是系统提供的方法实现的.   GCDAsyncSocket 对系统的方法进行了封装, 实例没有使用这个

/// 1 创建与服务器之间的链接,

-(void)creatConnectToServer{

  

  // 1.0 三次握手

    // CFAllocatorRef alloc:为通道开辟内存空间,如果传入 NULL就使用默认的

    // CFStringRef host : 服务器IP地址

    // UInt32 port : 服务器的端口号

    // CFReadStreamRef *readStream :输入流

    // CFWriteStreamRef *writeStream :输出流

    

    NSString * host =@"192.168.0.1";

    int port =12345;

    CFReadStreamRef readStream;

    CFWriteStreamRef writeStream;

    

    CFStreamCreatePairWithSocketToHost(NULL, (__bridgeCFStringRef)host , port, &readStream, &writeStream);

    

    // 1.0.1 为了操作方便 C语言的CFReadStreamRef, CFWriteStreamRef ,转化成OC语言的

    inputStream = (__bridgeNSInputStream *)readStream;

    outputStream = (__bridgeNSOutputStream *)writeStream;

    

    // 1.1 为输入输出流设置代理

    inputStream.delegate =self;

    outputStream.delegate =self;

    

    // 1.2 将输入输出流添加到主运行循环中 ,实现循环监听

    /*

     由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。

     */

    [inputStreamscheduleInRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];

    [outputStreamscheduleInRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];

    

    // 1.3 打开输入输出流

    [inputStreamopen];

    [outputStreamopen];


}

/// 2. 实现代理

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{


     /*

      NSStreamEventNone = 0,

      NSStreamEventOpenCompleted = 1UL << 0,

      NSStreamEventHasBytesAvailable = 1UL << 1,

      NSStreamEventHasSpaceAvailable = 1UL << 2,

      NSStreamEventErrorOccurred = 1UL << 3,

      NSStreamEventEndEncountered = 1UL << 4

      */

    

    switch (eventCode) {

        caseNSStreamEventNone:

            

            break;

        caseNSStreamEventOpenCompleted:

            // 连接成功

            

            break;

        caseNSStreamEventHasBytesAvailable:

            //  有数据可读

            [selfcreatReadRerverMessage];

            

            break;

        caseNSStreamEventHasSpaceAvailable:

            // 可以发送数据

            

            break;

        caseNSStreamEventErrorOccurred:

            // 出现错误,连接断开

            break;

        caseNSStreamEventEndEncountered:

            // 正常断开连接

            // 需要 1.关闭输入输出流, 2从主循环中移除

            [inputStreamclose];

            [outputStreamclose];

            [inputStreamremoveFromRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];

            [outputStreamremoveFromRunLoop:[NSRunLoopmainRunLoop]forMode:NSDefaultRunLoopMode];

            

            break;

            

        default:

            break;

    }

}

/// 3 实现登录点击登录时调用

-(void)creatLogin{

  // 登录是向服务器发送消息,输出流

  // 登录的格式,按照服务器的格式来写的,如本例服务器端规定 iam表示登录请求,那么前端要发起登录请求,就必须用 iam

    

    //

    NSString *login =@"iam: xiaoming";

    NSData *data = [logindataUsingEncoding:NSUTF8StringEncoding];

   

    // (const uint8_t *)buffer接收的是一个 char类型数组,所以要用data转一下

    // maxLength: 表示传输login的长度,这里是 login全部传输

    [outputStreamwrite: data.bytesmaxLength:data.length];


}


/// 4 读取服务器发送的消息需要在代理实现方法里调用

-(void)creatReadRerverMessage{

  //4.0 定义一个缓存区,从服务器读取的数据先放到缓存区,再转成相应格式

    uint8_t buf[1024];

  // 4.1 读取数据 ,返回的是实际接收到的数据长度

   NSInteger len = [inputStreamread:bufmaxLength:sizeof(buf)];

    // 4.2 转化格式

    NSString *receiverStr = [[NSStringalloc]initWithBytes:buflength:lenencoding:NSUTF8StringEncoding];

    NSLog(@"%@", receiverStr);

}


/// 5 向服务器发送消息,这个与登录类似,不同的是根据服务器的要求,登录消息的格式不同

-(void)creatSendMessageToSever:(NSString *)message{

  // 消息的格式,服务器要求用 msg表示所以要拼接

    NSString *str = [NSStringstringWithFormat:@"msg: %@",message];

    

    NSData *data = [strdataUsingEncoding:NSUTF8StringEncoding];

    [outputStreamwrite:data.bytesmaxLength:data.length];

    

   

}

本文参考  http://www.2cto.com/net/201211/166537.html


你可能感兴趣的:(tcp,UDP)