嵌入式学习——网络编程(TCP)——day31

1. TCP和UDP的区别

        TCP(Transmission Control Protocol,传输控制协议)

        UDP(User Datagram Protocol,用户数据报协议)

1.1 连接方式

  • TCP 是面向连接的协议,它在数据传输前需要通过三次握手建立一个可靠的连接,确保双方都准备好进行通信,并维护连接状态直到连接被明确关闭(四次挥手)。
  • UDP 是无连接的协议,它不建立正式的连接就可以直接发送数据包。发送端和接收端之间没有事先的握手过程,每个数据报都是独立发送的。

1.2 可靠性

  • TCP 提供可靠的数据传输服务,确保数据包按序、无损地到达接收端。它通过序列号、确认应答、错误检测、重传机制和流量控制来保证数据的可靠性和顺序。
  • UDP 不提供这些保障,数据包可能丢失、重复或乱序到达,适用于对实时性要求高于数据完整性的应用。

1.3 速度与效率

  • TCP 因其额外的控制信息和确认过程,相比UDP来说,传输效率较低,但提供了更高的可靠性。
  • UDP 由于其简单、无连接的特性,传输速度快,延迟低,适合实时应用。

1.4 数据包处理

  • TCP 将数据视为字节流,可以拆分和重组数据包,适合传输大量或连续的数据。
  • UDP 保留了数据报的边界,作为独立的数据单元传输,适合一次性传输小块或具有明确界限的数据。

1.5 应用场景

  • TCP 适用于需要高度可靠传输的应用,如Web浏览、电子邮件、文件传输(FTP)等。
  • UDP 适用于实时性要求高、可以容忍一定数据丢失的应用,如在线游戏、语音通话、视频流、DNS查询等。

1.6 资源消耗与复杂性

  • TCP 需要更多的系统资源来维护连接状态和执行复杂的错误恢复机制。
  • UDP 相对轻量,对系统资源的需求较少,程序实现也更为简单

2. TCP接口函数

2.1 socket

        socket(AF_INET, SOCK_STREAM, 0);

2.2 connect

          int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);
          功能:
            向接收端发送三次握手链接请求
          参数:
            sockfd:文件描述符
            addr:接收方地址空间首地址
            addrlen:接收方地址的大小
          返回值:
            成功返回0 
            失败返回-1 

2.3 send (发的太块会阻塞)

          ssize_t send(int sockfd, const void *buf, size_t len, int flags);
          功能:
            发送数据
          参数:
            sockfd:文件描述符
            buf:存放数据空间首地址
            len:发送数据长度
            flags:属性 默认为0 
          返回值:
            成功返回发送字节数
            失败返回-1 

2.4 recv

          ssize_t recv(int sockfd, void *buf, size_t len, int flags);
          功能:
            接收数据
          参数:
            sockfd:文件描述符
            buf:存放数据空间首地址 
            len:最多接收数据大小
            flags:属性 默认为0 
          返回值:
            成功返回实际接收字节数
            失败返回-1 
            对方关闭套接字返回0 

2.5 listen

          int listen(int sockfd, int backlog);
          功能:
            监听链接请求
          参数:
            sockfd:文件描述符
            backlog:允许最多等待链接的个数
          返回值:
            成功返回0 
            失败返回-1 

2.6 accept(返回通信套接字)

          int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
          功能:
            处理等待队列中第一个链接
          参数:
            sockfd:文件描述符 
            addr:存放链接对方地址信息空间首地址
            addrlen:想要接收地址大小变量空间首地址
          返回值:
            成功返回与发送端建立的新文件描述符(通信套接字)
            失败返回-1 
2.7 inet_addr

      in_addr_t inet_addr(const char *cp);
      功能:
        将字符串IP地址转换为二进制IP地址 
      参数:
        cp:字符串IP地址空间首地址
      返回值:
        成功返回二进制IP地址

2.8 htons

      uint16_t htons(uint16_t hostshort);
      功能:
        将本地字节序(小端)转换为网络字节序(大端)
      参数:
        hostshort:本地端口号
      返回值:
        返回网络字节序端口号
        
      uint16_t ntohs(uint16_t netshort);
      功能:
        将网络字节序(大端)转换为本地字节序(小端)

2.9 bind 

      int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);
      功能:
        将套接字与IP地址端口绑定在一起
      参数:
        sockfd:文件描述符 
        addr:结构体空间首地址 
        addrlen:信息的长度
      返回值:
        成功返回0 
        失败返回-1 

2.10 示例程序

(1)TCP单向通信

        1. 头文件

#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#endif

        2. makefile

all:send recv

send:send.c
	gcc $^ -o $@
recv:recv.c
	gcc $^ -o $@

        3. recv.c

#include "head.h"

int main(int argc, char const *argv[])
{
    int confd = 0;
    int listfd = 0;
    int ret_connect = 0;
    int ret_bind = 0;
    int ret_listen = 0;
    struct sockaddr_in recvaddr;
    struct sockaddr_in sendaddr;
    socklen_t addrlen = sizeof(sendaddr);
    ssize_t ret_send = 0;
    ssize_t ret_recv = 0;

    listfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == listfd)
    {
        perror("socket error!\n");
        return -1;
    }

    bzero(&recvaddr,sizeof(recvaddr));
    bzero(&sendaddr,sizeof(sendaddr));

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");

    ret_bind = bind(listfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret_bind)
    {
        perror("bind error!\n");
        return -1;
    }

    ret_listen = listen(listfd, 3);
    if (-1 == ret_listen)
    {
        perror("listen error!\n");
        return -1;     
    }

    confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
    if (-1 == confd)
    {
        perror("accept error!\n");
        return -1;  
    }

    while (1)
    {
        char buf[256] = {0};
 
        ret_recv = recv(confd, buf, sizeof(buf), 0);
        if (ret_recv <= 0)
        {
            break;
        }

        time_t tm;
        time(&tm);
        sprintf(buf, "%s %s", buf, ctime(&tm));

        ret_send = send(confd, buf, strlen(buf), 0);
        if (-1 == ret_send)
        {
            perror("send error!\n");
            return -1;        
        } 
    }
    
    close(confd);
    close(listfd);

    return 0;
}

        4. send.c

#include "head.h"

int main(int argc, char const *argv[])
{
    int confd = 0;
    int ret_connect = 0;
    struct sockaddr_in recvaddr;
    socklen_t addrlen = 0;
    ssize_t ret_send = 0;
    ssize_t ret_recv = 0;

    confd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == confd)
    {
        perror("socket error!\n");
        return -1;
    }

    bzero(&recvaddr, sizeof(recvaddr));

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");

    ret_connect = connect(confd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret_connect)
    {
        perror("connect error!\n");
        return -1;        
    }

    while (1)
    {
        char buf[256] = {"supercarrydoinb"};
        ret_send = send(confd, buf, strlen(buf), 0);
        if (-1 == ret_connect)
        {
            perror("send error!\n");
            return -1;        
        }  
        ret_recv = recv(confd, buf, sizeof(buf), 0);
        if (ret_recv <= 0)
        {
            break;
        }

        printf("%s", buf);
        sleep(1);
    }
    
    close(confd);

    return 0;
}

(2) TCP实现多线程双机聊天(chat)——注意:!!线程编译gcc要加后缀 -lpthread

        1. 头文件

#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#endif

        2. makefile

all:send recv

send:send.c
	gcc $^ -o $@ -lpthread
recv:recv.c
	gcc $^ -o $@ -lpthread

        3. send.c

#include "head.h"

struct sockaddr_in sendaddr;
struct sockaddr_in recvaddr;

void *th1(void *arg)
{
    int confd = *(int *)arg;
    ssize_t ret_recv = 0;
    while (1)
    {
        char buf[256] = {0};
        ret_recv = recv(confd, buf, sizeof(buf), 0);
        if (-1 == ret_recv)
        {
            perror("recv error!\n");
        }
        printf("from recv: %s\n", buf);
    }
}

void *th2(void *arg)
{
    int confd = *(int *)arg;
    ssize_t ret_send = 0;
    while (1)
    {
        printf("to recv:");
        char buf[256] = {0};
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf)-1] = '\0';
        ret_send= send(confd, buf, strlen(buf), 0);
        if (-1 == ret_send)
        {
            perror("send error!\n");
        }
    }
}

int main(int argc, char const *argv[])
{
    int confd = 0;
    int ret_connect = 0;
    socklen_t addrlen = sizeof(sendaddr);
    ssize_t ret_recv = 0;
    ssize_t ret_send = 0;
    pthread_t tid1;
    pthread_t tid2;
    char buf[256] = {0};

    confd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == confd)
    {
        perror("socket error!\n");
        return -1;
    }

    bzero(&recvaddr, sizeof(recvaddr));
    bzero(&sendaddr, sizeof(sendaddr));

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");

    ret_connect = connect(confd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret_connect)
    {
        perror("connect error!\n");
        return -1;
    }
    
#if 0
    ret_recv = recv(confd, buf, sizeof(buf), 0);
    if (-1 == ret_recv)
    {
        perror("recv error!\n");
        return -1;
    }
#endif

    pthread_create(&tid1, NULL, th1, &confd);
    pthread_create(&tid2, NULL, th2, &confd);

    pthread_join(tid1, NULL);
    pthread_join(tid1, NULL);
    
    return 0;
}

        4. recv.c

#include "head.h"

struct sockaddr_in sendaddr;
struct sockaddr_in recvaddr;

void *th1(void *arg)
{
    int confd = *(int *)arg;
    ssize_t ret_recv = 0;
    while (1)
    {
        char buf[256] = {0};
        ret_recv = recv(confd, buf, sizeof(buf), 0);
        if (-1 == ret_recv)
        {
            perror("recv error!\n");
        }
        printf("from send: %s\n", buf);
    }
}

void *th2(void *arg)
{
    int confd = *(int *)arg;
    ssize_t ret_send = 0;
    while (1)
    {
        printf("to send:");
        char buf[256] = {0};
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf)-1] = '\0';
        ret_send = send(confd, buf, strlen(buf), 0);
        if (-1 == ret_send)
        {
            perror("send error!\n");
        }
    }
}

int main(int argc, char const *argv[])
{
    int listfd = 0;
    int confd = 0;
    int ret_bind = 0;
    int ret_listen = 0;
    socklen_t addrlen = sizeof(sendaddr);
    ssize_t ret_recv = 0;
    ssize_t ret_send = 0;
    pthread_t tid1;
    pthread_t tid2;
    char buf[256] = {0};

    listfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == listfd)
    {
        perror("socket error!\n");
        return -1;
    }

    bzero(&recvaddr, sizeof(recvaddr));
    bzero(&sendaddr, sizeof(sendaddr));

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");

    ret_bind = bind(listfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret_bind)
    {
        perror("bind error!\n");
        return -1;
    }

    ret_listen = listen(listfd, 3);
    if (-1 == ret_listen)
    {
        perror("listen error!\n");
        return -1;        
    }

    confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
    if (-1 == confd)
    {
        perror("accept error!\n");
        return -1;         
    }
    
#if 0
    ret_recv = recv(confd, buf, sizeof(buf), 0);
    if (-1 == ret_recv)
    {
        perror("recv error!\n");
        return -1;
    }
#endif

    pthread_create(&tid1, NULL, th1, &confd);
    pthread_create(&tid2, NULL, th2, &confd);

    pthread_join(tid1, NULL);
    pthread_join(tid1, NULL);
    
    return 0;
}

(3) TCP实现文件的传输(结构体)

        1. 头文件

#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <arpa/inet.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#endif

        2. makefile

all:send recv

send:send.c
	gcc $^ -o $@ -lpthread
recv:recv.c
	gcc $^ -o $@ -lpthread

        3. send.c

#include "head.h"

typedef struct 
{
    char buf[1024];
    char filename[32];
    int rd_ret;
    int total;
}MSG;

int main(int argc, char const *argv[])
{
    int ret_connect = 0;
    int ret_stat = 0;
    int confd = 0;
    int openfd = 0;
    ssize_t ret_recv = 0;
    ssize_t ret_send = 0;
    struct sockaddr_in recvaddr;
    MSG msg;
    struct stat st;

    confd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == confd)
    {
        perror("socket error!\n");
        return -1;
    }

    bzero(&recvaddr, sizeof(recvaddr));
    bzero(&msg, sizeof(msg));

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");

    ret_connect = connect(confd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret_connect)
    {
        perror("connetc error!\n");
        return -1;
    }

    openfd = open("./1.png", O_RDONLY);
    if (-1 == openfd)
    {
        perror("open error!\n");
        return -1;
    }

    strcpy(msg.filename, "2.png");

    ret_stat = stat("./1.png", &st);
    if (-1 == ret_stat)
    {
        perror("stat error!\n");
        return -1;
    }
    msg.total = st.st_size;

    while (1)
    {
        bzero(msg.buf, sizeof(msg.buf));

        msg.rd_ret = read(openfd, msg.buf, sizeof(msg.buf));
        send(confd, &msg, sizeof(msg), 0);
        if (msg.rd_ret <= 0)
        {
            break;
        }
        char buf[256] = {0};
        ret_recv = recv(confd, buf, sizeof(buf), 0);
        if (ret_recv <= 0)
        {
            break;
        }
        usleep(1000 * 200);
    }

    close(confd);
    close(openfd);

    return 0;
}

        4. recv.c

#include "head.h"

typedef struct 
{
    char buf[1024];
    char filename[32];
    int rd_ret;
    int total;
}MSG;

int main(int argc, char const *argv[])
{
    int listfd = 0;
    int ret_bind = 0;
    int ret_listen = 0;
    int confd = 0;
    ssize_t ret_recv = 0;
    ssize_t ret_send = 0;
    struct sockaddr_in recvaddr;
    struct sockaddr_in sendaddr;
    socklen_t addrlen = sizeof(sendaddr);
    MSG msg;

    listfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == listfd)
    {
        perror("socket error!\n");
        return -1;
    }

    bzero(&recvaddr, sizeof(recvaddr));
    bzero(&sendaddr, sizeof(sendaddr));
    bzero(&msg, sizeof(msg));

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(50000);
    recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");

    ret_bind = bind(listfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret_bind)
    {
        perror("bind error!\n");
        return -1;
    }


    ret_listen = listen(listfd, 3);
    if (-1 == ret_listen)
    {
        perror("listen error!\n");
        return -1;
    }

    confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
    if (-1 == confd)
    {
        perror("accept error!\n");
        return -1;
    }

    int openfd = 0;
    int flag = 0;
    int total = 0;
    int current_size = 0;
    while (1)
    {
        ret_recv = recv(confd, &msg, sizeof(msg), 0);
        if (ret_recv <= 0)
        {
            break;
        }

        if (0 == msg.rd_ret)
        {
            printf("file upload end\n");
            return -1;
        }

        if (0 == flag)//拿到文件总大小
        {
            openfd = open(msg.filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
            if (-1 == openfd)
            {
                perror("open error!\n");
                return -1;
            }

            flag = 1;
            total = msg.total;
        }

        write(openfd, msg.buf, msg.rd_ret);
        current_size += msg.rd_ret;
        printf("%d / %d\n", current_size, total);
        char buf[256] = "go on";
        send(confd, buf, strlen(buf), 0);
    }

    close(confd);
    close(openfd);
    close(listfd);

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值