当前位置:   article > 正文

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

嵌入式学习——网络编程(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. 头文件

  1. #ifndef _HEAD_H_
  2. #define _HEAD_H_
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sys/types.h> /* See NOTES */
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <netinet/ip.h>
  14. #include <arpa/inet.h>
  15. #include <time.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <pthread.h>
  19. #endif

        2. makefile

  1. all:send recv
  2. send:send.c
  3. gcc $^ -o $@
  4. recv:recv.c
  5. gcc $^ -o $@

        3. recv.c

  1. #include "head.h"
  2. int main(int argc, char const *argv[])
  3. {
  4. int confd = 0;
  5. int listfd = 0;
  6. int ret_connect = 0;
  7. int ret_bind = 0;
  8. int ret_listen = 0;
  9. struct sockaddr_in recvaddr;
  10. struct sockaddr_in sendaddr;
  11. socklen_t addrlen = sizeof(sendaddr);
  12. ssize_t ret_send = 0;
  13. ssize_t ret_recv = 0;
  14. listfd = socket(AF_INET, SOCK_STREAM, 0);
  15. if (-1 == listfd)
  16. {
  17. perror("socket error!\n");
  18. return -1;
  19. }
  20. bzero(&recvaddr,sizeof(recvaddr));
  21. bzero(&sendaddr,sizeof(sendaddr));
  22. recvaddr.sin_family = AF_INET;
  23. recvaddr.sin_port = htons(50000);
  24. recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");
  25. ret_bind = bind(listfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
  26. if (-1 == ret_bind)
  27. {
  28. perror("bind error!\n");
  29. return -1;
  30. }
  31. ret_listen = listen(listfd, 3);
  32. if (-1 == ret_listen)
  33. {
  34. perror("listen error!\n");
  35. return -1;
  36. }
  37. confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
  38. if (-1 == confd)
  39. {
  40. perror("accept error!\n");
  41. return -1;
  42. }
  43. while (1)
  44. {
  45. char buf[256] = {0};
  46. ret_recv = recv(confd, buf, sizeof(buf), 0);
  47. if (ret_recv <= 0)
  48. {
  49. break;
  50. }
  51. time_t tm;
  52. time(&tm);
  53. sprintf(buf, "%s %s", buf, ctime(&tm));
  54. ret_send = send(confd, buf, strlen(buf), 0);
  55. if (-1 == ret_send)
  56. {
  57. perror("send error!\n");
  58. return -1;
  59. }
  60. }
  61. close(confd);
  62. close(listfd);
  63. return 0;
  64. }

        4. send.c

  1. #include "head.h"
  2. int main(int argc, char const *argv[])
  3. {
  4. int confd = 0;
  5. int ret_connect = 0;
  6. struct sockaddr_in recvaddr;
  7. socklen_t addrlen = 0;
  8. ssize_t ret_send = 0;
  9. ssize_t ret_recv = 0;
  10. confd = socket(AF_INET, SOCK_STREAM, 0);
  11. if (-1 == confd)
  12. {
  13. perror("socket error!\n");
  14. return -1;
  15. }
  16. bzero(&recvaddr, sizeof(recvaddr));
  17. recvaddr.sin_family = AF_INET;
  18. recvaddr.sin_port = htons(50000);
  19. recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");
  20. ret_connect = connect(confd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
  21. if (-1 == ret_connect)
  22. {
  23. perror("connect error!\n");
  24. return -1;
  25. }
  26. while (1)
  27. {
  28. char buf[256] = {"supercarrydoinb"};
  29. ret_send = send(confd, buf, strlen(buf), 0);
  30. if (-1 == ret_connect)
  31. {
  32. perror("send error!\n");
  33. return -1;
  34. }
  35. ret_recv = recv(confd, buf, sizeof(buf), 0);
  36. if (ret_recv <= 0)
  37. {
  38. break;
  39. }
  40. printf("%s", buf);
  41. sleep(1);
  42. }
  43. close(confd);
  44. return 0;
  45. }

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

        1. 头文件

  1. #ifndef _HEAD_H_
  2. #define _HEAD_H_
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sys/types.h> /* See NOTES */
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <netinet/ip.h>
  14. #include <arpa/inet.h>
  15. #include <time.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <pthread.h>
  19. #endif

        2. makefile

  1. all:send recv
  2. send:send.c
  3. gcc $^ -o $@ -lpthread
  4. recv:recv.c
  5. gcc $^ -o $@ -lpthread

        3. send.c

  1. #include "head.h"
  2. struct sockaddr_in sendaddr;
  3. struct sockaddr_in recvaddr;
  4. void *th1(void *arg)
  5. {
  6. int confd = *(int *)arg;
  7. ssize_t ret_recv = 0;
  8. while (1)
  9. {
  10. char buf[256] = {0};
  11. ret_recv = recv(confd, buf, sizeof(buf), 0);
  12. if (-1 == ret_recv)
  13. {
  14. perror("recv error!\n");
  15. }
  16. printf("from recv: %s\n", buf);
  17. }
  18. }
  19. void *th2(void *arg)
  20. {
  21. int confd = *(int *)arg;
  22. ssize_t ret_send = 0;
  23. while (1)
  24. {
  25. printf("to recv:");
  26. char buf[256] = {0};
  27. fgets(buf, sizeof(buf), stdin);
  28. buf[strlen(buf)-1] = '\0';
  29. ret_send= send(confd, buf, strlen(buf), 0);
  30. if (-1 == ret_send)
  31. {
  32. perror("send error!\n");
  33. }
  34. }
  35. }
  36. int main(int argc, char const *argv[])
  37. {
  38. int confd = 0;
  39. int ret_connect = 0;
  40. socklen_t addrlen = sizeof(sendaddr);
  41. ssize_t ret_recv = 0;
  42. ssize_t ret_send = 0;
  43. pthread_t tid1;
  44. pthread_t tid2;
  45. char buf[256] = {0};
  46. confd = socket(AF_INET, SOCK_STREAM, 0);
  47. if (-1 == confd)
  48. {
  49. perror("socket error!\n");
  50. return -1;
  51. }
  52. bzero(&recvaddr, sizeof(recvaddr));
  53. bzero(&sendaddr, sizeof(sendaddr));
  54. recvaddr.sin_family = AF_INET;
  55. recvaddr.sin_port = htons(50000);
  56. recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");
  57. ret_connect = connect(confd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
  58. if (-1 == ret_connect)
  59. {
  60. perror("connect error!\n");
  61. return -1;
  62. }
  63. #if 0
  64. ret_recv = recv(confd, buf, sizeof(buf), 0);
  65. if (-1 == ret_recv)
  66. {
  67. perror("recv error!\n");
  68. return -1;
  69. }
  70. #endif
  71. pthread_create(&tid1, NULL, th1, &confd);
  72. pthread_create(&tid2, NULL, th2, &confd);
  73. pthread_join(tid1, NULL);
  74. pthread_join(tid1, NULL);
  75. return 0;
  76. }

        4. recv.c

  1. #include "head.h"
  2. struct sockaddr_in sendaddr;
  3. struct sockaddr_in recvaddr;
  4. void *th1(void *arg)
  5. {
  6. int confd = *(int *)arg;
  7. ssize_t ret_recv = 0;
  8. while (1)
  9. {
  10. char buf[256] = {0};
  11. ret_recv = recv(confd, buf, sizeof(buf), 0);
  12. if (-1 == ret_recv)
  13. {
  14. perror("recv error!\n");
  15. }
  16. printf("from send: %s\n", buf);
  17. }
  18. }
  19. void *th2(void *arg)
  20. {
  21. int confd = *(int *)arg;
  22. ssize_t ret_send = 0;
  23. while (1)
  24. {
  25. printf("to send:");
  26. char buf[256] = {0};
  27. fgets(buf, sizeof(buf), stdin);
  28. buf[strlen(buf)-1] = '\0';
  29. ret_send = send(confd, buf, strlen(buf), 0);
  30. if (-1 == ret_send)
  31. {
  32. perror("send error!\n");
  33. }
  34. }
  35. }
  36. int main(int argc, char const *argv[])
  37. {
  38. int listfd = 0;
  39. int confd = 0;
  40. int ret_bind = 0;
  41. int ret_listen = 0;
  42. socklen_t addrlen = sizeof(sendaddr);
  43. ssize_t ret_recv = 0;
  44. ssize_t ret_send = 0;
  45. pthread_t tid1;
  46. pthread_t tid2;
  47. char buf[256] = {0};
  48. listfd = socket(AF_INET, SOCK_STREAM, 0);
  49. if (-1 == listfd)
  50. {
  51. perror("socket error!\n");
  52. return -1;
  53. }
  54. bzero(&recvaddr, sizeof(recvaddr));
  55. bzero(&sendaddr, sizeof(sendaddr));
  56. recvaddr.sin_family = AF_INET;
  57. recvaddr.sin_port = htons(50000);
  58. recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");
  59. ret_bind = bind(listfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
  60. if (-1 == ret_bind)
  61. {
  62. perror("bind error!\n");
  63. return -1;
  64. }
  65. ret_listen = listen(listfd, 3);
  66. if (-1 == ret_listen)
  67. {
  68. perror("listen error!\n");
  69. return -1;
  70. }
  71. confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
  72. if (-1 == confd)
  73. {
  74. perror("accept error!\n");
  75. return -1;
  76. }
  77. #if 0
  78. ret_recv = recv(confd, buf, sizeof(buf), 0);
  79. if (-1 == ret_recv)
  80. {
  81. perror("recv error!\n");
  82. return -1;
  83. }
  84. #endif
  85. pthread_create(&tid1, NULL, th1, &confd);
  86. pthread_create(&tid2, NULL, th2, &confd);
  87. pthread_join(tid1, NULL);
  88. pthread_join(tid1, NULL);
  89. return 0;
  90. }

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

        1. 头文件

  1. #ifndef _HEAD_H_
  2. #define _HEAD_H_
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <sys/types.h> /* See NOTES */
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <netinet/ip.h>
  14. #include <arpa/inet.h>
  15. #include <time.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <pthread.h>
  19. #endif

        2. makefile

  1. all:send recv
  2. send:send.c
  3. gcc $^ -o $@ -lpthread
  4. recv:recv.c
  5. gcc $^ -o $@ -lpthread

        3. send.c

  1. #include "head.h"
  2. typedef struct
  3. {
  4. char buf[1024];
  5. char filename[32];
  6. int rd_ret;
  7. int total;
  8. }MSG;
  9. int main(int argc, char const *argv[])
  10. {
  11. int ret_connect = 0;
  12. int ret_stat = 0;
  13. int confd = 0;
  14. int openfd = 0;
  15. ssize_t ret_recv = 0;
  16. ssize_t ret_send = 0;
  17. struct sockaddr_in recvaddr;
  18. MSG msg;
  19. struct stat st;
  20. confd = socket(AF_INET, SOCK_STREAM, 0);
  21. if (-1 == confd)
  22. {
  23. perror("socket error!\n");
  24. return -1;
  25. }
  26. bzero(&recvaddr, sizeof(recvaddr));
  27. bzero(&msg, sizeof(msg));
  28. recvaddr.sin_family = AF_INET;
  29. recvaddr.sin_port = htons(50000);
  30. recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");
  31. ret_connect = connect(confd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
  32. if (-1 == ret_connect)
  33. {
  34. perror("connetc error!\n");
  35. return -1;
  36. }
  37. openfd = open("./1.png", O_RDONLY);
  38. if (-1 == openfd)
  39. {
  40. perror("open error!\n");
  41. return -1;
  42. }
  43. strcpy(msg.filename, "2.png");
  44. ret_stat = stat("./1.png", &st);
  45. if (-1 == ret_stat)
  46. {
  47. perror("stat error!\n");
  48. return -1;
  49. }
  50. msg.total = st.st_size;
  51. while (1)
  52. {
  53. bzero(msg.buf, sizeof(msg.buf));
  54. msg.rd_ret = read(openfd, msg.buf, sizeof(msg.buf));
  55. send(confd, &msg, sizeof(msg), 0);
  56. if (msg.rd_ret <= 0)
  57. {
  58. break;
  59. }
  60. char buf[256] = {0};
  61. ret_recv = recv(confd, buf, sizeof(buf), 0);
  62. if (ret_recv <= 0)
  63. {
  64. break;
  65. }
  66. usleep(1000 * 200);
  67. }
  68. close(confd);
  69. close(openfd);
  70. return 0;
  71. }

        4. recv.c

  1. #include "head.h"
  2. typedef struct
  3. {
  4. char buf[1024];
  5. char filename[32];
  6. int rd_ret;
  7. int total;
  8. }MSG;
  9. int main(int argc, char const *argv[])
  10. {
  11. int listfd = 0;
  12. int ret_bind = 0;
  13. int ret_listen = 0;
  14. int confd = 0;
  15. ssize_t ret_recv = 0;
  16. ssize_t ret_send = 0;
  17. struct sockaddr_in recvaddr;
  18. struct sockaddr_in sendaddr;
  19. socklen_t addrlen = sizeof(sendaddr);
  20. MSG msg;
  21. listfd = socket(AF_INET, SOCK_STREAM, 0);
  22. if (-1 == listfd)
  23. {
  24. perror("socket error!\n");
  25. return -1;
  26. }
  27. bzero(&recvaddr, sizeof(recvaddr));
  28. bzero(&sendaddr, sizeof(sendaddr));
  29. bzero(&msg, sizeof(msg));
  30. recvaddr.sin_family = AF_INET;
  31. recvaddr.sin_port = htons(50000);
  32. recvaddr.sin_addr.s_addr = inet_addr("192.168.0.109");
  33. ret_bind = bind(listfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
  34. if (-1 == ret_bind)
  35. {
  36. perror("bind error!\n");
  37. return -1;
  38. }
  39. ret_listen = listen(listfd, 3);
  40. if (-1 == ret_listen)
  41. {
  42. perror("listen error!\n");
  43. return -1;
  44. }
  45. confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
  46. if (-1 == confd)
  47. {
  48. perror("accept error!\n");
  49. return -1;
  50. }
  51. int openfd = 0;
  52. int flag = 0;
  53. int total = 0;
  54. int current_size = 0;
  55. while (1)
  56. {
  57. ret_recv = recv(confd, &msg, sizeof(msg), 0);
  58. if (ret_recv <= 0)
  59. {
  60. break;
  61. }
  62. if (0 == msg.rd_ret)
  63. {
  64. printf("file upload end\n");
  65. return -1;
  66. }
  67. if (0 == flag)//拿到文件总大小
  68. {
  69. openfd = open(msg.filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  70. if (-1 == openfd)
  71. {
  72. perror("open error!\n");
  73. return -1;
  74. }
  75. flag = 1;
  76. total = msg.total;
  77. }
  78. write(openfd, msg.buf, msg.rd_ret);
  79. current_size += msg.rd_ret;
  80. printf("%d / %d\n", current_size, total);
  81. char buf[256] = "go on";
  82. send(confd, buf, strlen(buf), 0);
  83. }
  84. close(confd);
  85. close(openfd);
  86. close(listfd);
  87. return 0;
  88. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/686064
推荐阅读
相关标签
  

闽ICP备14008679号