zoukankan      html  css  js  c++  java
  • LINUX下 基于 Socket 的 UDP 和 TCP 编程具体实现

    基于 Socket 的 UDP 和 TCP 编程介绍

    一、概述

    TCP(传输控制协议)和UDP(用户数据报协议是网络体系结TCP/IP模型中传输层一层中的两个不同的通信协议。

    TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流,TCP套接口是字节流套接口(stream socket)的一种。

    UDP:用户数据报协议。UDP是一种无连接协议。UDP套接口是数据报套接口(datagram socket)的一种。

    二、TCP和UDP介绍

    1)基本TCP客户—服务器程序设计基本框架

    说明:(三路握手)

    1.客户端发送一个SYN段(同步序号)指明客户打算连接的服务器端口,以及初始化序号(ISN) 。

    2.服务器发回包含服务器的初始序号的SYN报文段作为应答。同时,将确认序号(ACK)设置为客户的ISN加1以对客户的SYN 报文段进行确认。一个SYN将占用一个序号。

    3.客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认。

    2) 基本TCP客户—服务器程序设计基本框架流程图

    3) UDP和TCP的对比:


    从上面的流程图比较我们可以很明显的看出UDP没有三次握手过程。简单点说。UDP处理的细节比TCP少。UDP不能保证消息被传送到(它也报告消息没有传送到)目的地。UDP也不保证数据包的传送顺序。UDP把数据发出去后只能希望它能够抵达目的地。

    TCP优缺点:


    优点:


    1.TCP提供以认可的方式显式地创建和终止连接。
    2.TCP保证可靠的、顺序的(数据包以发送的顺序接收)以及不会重复的数据传输。
    3.TCP处理流控制。
    4.允许数据优先
    5.如果数据没有传送到,则TCP套接口返回一个出错状态条件。
    6.TCP通过保持连续并将数据块分成更小的分片来处理大数据块。—无需程序员知道

    缺点: TCP在转移数据时必须创建(并保持)一个连接。这个连接给通信进程增加了开销,让它比UDP速度要慢。

    UDP优缺点:


    1.UDP不要求保持一个连接
    2.UDP没有因接收方认可收到数据包(或者当数据包没有正确抵达而自动重传)而带来的开销。
    3.设计UDP的目的是用于短应用和控制消息
    4.在一个数据包连接一个数据包的基础上,UDP要求的网络带宽比TDP更小。

     

    三、Socket编程

    Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。

    Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。

    常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

    1、socket调用库函数主要有:


    创建套接字

    Socket(af,type,protocol)

    建立地址和套接字的联系

    bind(sockid, local addr, addrlen)

    服务器端侦听客户端的请求

    listen( Sockid ,quenlen)


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

    客户端请求连接

    Connect(sockid, destaddr, addrlen)


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

    newsockid=accept(Sockid,Clientaddr, paddrlen)

    发送/接收数据


    面向连接:

    send(sockid, buff, bufflen)


    recv( )


    面向无连接:

    sendto(sockid,buff,…,addrlen)

    recvfrom( )


    释放套接字

    close(sockid)

    2、TCP/IP应用编程接口(API)

          客户端代码:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/shm.h>
    
    #define MYPORT  8887
    #define BUFFER_SIZE 1024
    
    int main()
    {
        ///定义sockfd
        int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    
        ///定义sockaddr_in
        struct sockaddr_in servaddr;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(MYPORT);  ///服务器端口
        servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip
    
        ///连接服务器,成功返回0,错误返回-1
        if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
        {
            perror("connect");
            exit(1);
        }
    
        char sendbuf[BUFFER_SIZE];
        char recvbuf[BUFFER_SIZE];
        while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
        {
            send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送
            if(strcmp(sendbuf,"exit
    ")==0)
                break;
            recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收
            fputs(recvbuf, stdout);
    
            memset(sendbuf, 0, sizeof(sendbuf));
            memset(recvbuf, 0, sizeof(recvbuf));
        }
    
        close(sock_cli);
        return 0;
    }

    服务端代码:

     1 #include <sys/types.h>
     2 #include <sys/socket.h>
     3 #include <stdio.h>
     4 #include <netinet/in.h>
     5 #include <arpa/inet.h>
     6 #include <unistd.h>
     7 #include <string.h>
     8 #include <stdlib.h>
     9 #include <fcntl.h>
    10 #include <sys/shm.h>
    11 
    12 #define MYPORT  8887
    13 #define QUEUE   20
    14 #define BUFFER_SIZE 1024
    15 
    16 int main()
    17 {
    18     ///定义sockfd
    19     int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
    20 
    21     ///定义sockaddr_in
    22     struct sockaddr_in server_sockaddr;
    23     server_sockaddr.sin_family = AF_INET;
    24     server_sockaddr.sin_port = htons(MYPORT);
    25     server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    26 
    27     ///bind,成功返回0,出错返回-1
    28     if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
    29     {
    30         perror("bind");
    31         exit(1);
    32     }
    33 
    34     ///listen,成功返回0,出错返回-1
    35     if(listen(server_sockfd,QUEUE) == -1)
    36     {
    37         perror("listen");
    38         exit(1);
    39     }
    40 
    41     ///客户端套接字
    42     char buffer[BUFFER_SIZE];
    43     struct sockaddr_in client_addr;
    44     socklen_t length = sizeof(client_addr);
    45 
    46     ///成功返回非负描述字,出错返回-1
    47     int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
    48     if(conn<0)
    49     {
    50         perror("connect");
    51         exit(1);
    52     }
    53 
    54     while(1)
    55     {
    56         memset(buffer,0,sizeof(buffer));
    57         int len = recv(conn, buffer, sizeof(buffer),0);
    58         if(strcmp(buffer,"exit
    ")==0)
    59             break;
    60         fputs(buffer, stdout);
    61         send(conn, buffer, len, 0);
    62     }
    63     close(conn);
    64     close(server_sockfd);
    65     return 0;
    66 }

    编译源程序

    gcc  service.c  -o  service

    gcc client.c  -o  client

    三、调试

    打开终端先运行服务端程序   ./service

    再打开另一个终端运行客户端程序   ./client

    在client 中随意输入     一串字符     服务端会出现字符    并且返回给客户端一样的字符

    运行结果如图:


  • 相关阅读:
    PNG文件格式具体解释
    opencv2对读书笔记——使用均值漂移算法查找物体
    Jackson的Json转换
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 单词接龙
  • 原文地址:https://www.cnblogs.com/yamin-wanghc/p/6029022.html
Copyright © 2011-2022 走看看