Socket-TCP/UDP浅析

TCP与UDP传输协议浅析

对于这个问题,相信刚接触开发的人遇到的比较频繁,很多开发术语说出来的知识概念显得很高深,很难,其实不是,等你自己打通一条UDP/TCP通信,实现传输的时候,发现还是很易使用的。

二者差异:
1、TCP面向连接;UDP是无连接的。
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低。
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节。

这里列举了几条,其实要详述差异还有很多很多,其内部复杂的通信实现,作为一位普通的开发人员不需要了解,我们只要达到可以在适合的场合,使用适合的通信方式即可。(通俗的理解:TCP似一条河流,要想流通,必须建立河道,传输是不间断的发送流,而且会出现阻塞。但毕竟是河道是唯一的,通信安全可靠,而UDP是将数据分包,每次会发送一个包出去,到指定的sever和port,可以是一,也可以是多,不需要建立不间断连接,所以可靠性相对低一些(我发了10条,你网络不好,接收7条,发送到仍然会认为数据发送完毕))。

1、UDP实现

{
    struct sockaddr_in si_other;
    int _socket,addled;
    char buf[BUFLEN];//存储接收状态
}
//用于设置发送超时
static sigjmp_buf recv_timed_out;
void timeout_handler (int signum)
{
    signal(SIGALRM, SIG_DFL);
    siglongjmp(recv_timed_out, 1);
}
//socket初始化sever为ip地址,port为端口号
addlen = sizeof(si_other);
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(port);
inet_aton([server UTF8String] , &si_other.sin_addr);
_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//发送data数据到指定sever
- (NSString *)sendTheMessage:(NSData *)data{
    //发送数据
    if (_socket<0) {
        NSLog(@"failed to create socket");
    }
    NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    long status_send = sendto(_socket, [message UTF8String], strlen([message UTF8String]), 0, (struct sockaddr *)&si_other, addlen);
    if (status_send == -1) {
        NSLog(@"failed to send");
    }
    //发送超时设置
    struct timeval timeout = {5,0};
    setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
    //接收返回状态buf
    memset(buf,'\0', BUFLEN);
    long status_receive = recvfrom(_socket, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &addlen);
    if (status_receive == -1) {
        NSLog(@"failed to receive ,time out!");
    }
    return [NSString stringWithUTF8String:buf];
}

以上就是个简单的UDP实现,发送什么,返回什么,都是开发与后台之间共同决定的。

2、TCP实现

static const unsigned int READ_BUFFER_SIZE = 1024;

@interface TCP ()
{
    struct sockaddr_in serverAddress;
    int _socket;
    unsigned char * _readBuffer;
    volatile BOOL _isConnected;
    NSString * _className;
    volatile BOOL _isReleasedBuffer;
}
@end

@implementation TCP
//初始化sever的基础信息
- (instancetype)initWithAddress:(NSString *)address Port:(int)port{
    self = [super init];
    if (self) {
        serverAddress.sin_len = sizeof(struct sockaddr_in);
        serverAddress.sin_family = AF_INET;
        serverAddress.sin_port = htons(port);
        serverAddress.sin_addr.s_addr = inet_addr([address UTF8String]);
        bzero(&(serverAddress.sin_zero),8);
        _readBuffer = malloc(READ_BUFFER_SIZE);
        bzero(_readBuffer, 0);
        _isReleasedBuffer = NO;
        _className = @"Socket";
    }
    return self;
}
//建立socket,设置读写延时,建立client和sever的连接
- (BOOL)connect{
    //init socket
    _socket = socket(AF_INET, SOCK_STREAM, 0);
    struct timeval resvTimeoutPramaters;
    struct timeval sendTimeoutParameters;

    //set read timeout
    resvTimeoutPramaters.tv_sec = 3;
    resvTimeoutPramaters.tv_usec = 1500;
    int errorCode = setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, &resvTimeoutPramaters, sizeof(struct timeval));
    if(errorCode < 0){
        NSLog(@"[%@] setsockopt revtimeo error is %d", _className, errorCode);
        return NO;
    }

    //set send timeout
    sendTimeoutParameters.tv_sec = 3;
    sendTimeoutParameters.tv_usec = 1500;
    errorCode = setsockopt(_socket, SOL_SOCKET, SO_SNDTIMEO, &sendTimeoutParameters, sizeof(struct timeval));
    if(errorCode < 0){
        NSLog(@"[%@] setsockopt sedtimeo error is %d", _className, errorCode);
        return NO;
    }
    // in case of SIGPIPE signal happens.
    int set = 1;
    setsockopt(_socket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));

    // check whether a socket is established succesfully
    if(_socket == -1){
        NSLog(@"[%@] socket created failed", _className);
        return NO;
    }

    // try to connect
    if (connect(_socket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in))==0) {
        _isConnected = YES;
        return YES;
    }
    NSLog(@"[%@] socket connected failed", _className);

    return NO;
}
//关闭socket
- (void)closeSocket{
    @synchronized(self){
        close(_socket);
        if(!_isReleasedBuffer){
            free(_readBuffer);
            _isReleasedBuffer = YES;
        }
    }
}
//TCP是面向连接的,使用send发送数据
char buf[1024];
do {
    printf("input message:");
    scanf("%s",buf);
    send(fd, buf, 1024, 0);
} while (strcmp(buf, "exit")!=0);

socket调用库函数主要有:
创建套接字

   Socket(af,type,protocol)

建立地址和套接字的联系(sever端使用)

   bind(sockid, local addr, addrlen)

服务器端侦听客户端的请求(sever段使用)

   listen( Sockid ,quenlen)

建立服务器/客户端的连接 (面向连接TCP)

客户端请求连接

    Connect(sockid, destaddr, addrlen)

服务器端等待从编号为Sockid的Socket上接收客户连接请求

    newsockid=accept(Sockid,Clientaddr, paddrlen)

发送/接收数据

面向连接:(TCP连接发送使用)

    send(sockid, buff, bufflen) 
    recv( )

面向无连接:(UDP无连接发送使用)

    sendto(sockid,buff,…,addrlen) 
    recvfrom( )

释放套接字

    close(sockid)

socket的简单使用就这些,其内部的理论在各大网站上都有描述,会对C方法内部的具体过程进行详细的讲解,这里就不做描述了。github上的socket开源项目,这个可以直接使用。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值