嵌入式学习——Linux高级编程复习(TCP编程)——day44

基于TCP聊天:
    clientA.c                     clientB.c 

    socket                                socket 
    connect                              bind 
                                               listen
                                               accept

                                
    pthread_create 
    pthread_create                pthread_create
    pthread_join                    pthread_create
    pthread_join                    pthread_join
                                            pthread_join

1. TCP编程——函数接口

1.1 socket(首先监听套接字)

        1. 定义

              int socket(int domain, int type, int protocol);

        2. 功能

                创建一个用来进程通信的套接字,返回文件描述符

        3. 参数

                domain:AF_INET           IPv4协议族
                type:SOCK_STREAM    流式套接字            tcp传输协议
                        SOCK_DGRAM    数据报套接字            udp传输协议
                        SOCK_RAW        原始套接字            
                protocol:
                        默认为0 

        4. 返回值

                成功返回套接字新文件描述符
                失败返回-1 

        5. 注意

1.2 inet_addr

        1. 定义

              in_addr_t inet_addr(const char *cp);

        2. 功能

                将字符串IP地址转换为二进制IP地址 

        3. 参数

                cp:字符串IP地址空间首地址

        4. 返回值

                成功返回二进制IP地址

        5. 注意

1.3 htons

        1. 定义

              uint16_t htons(uint16_t hostshort);

        2. 功能

                将本地字节序(小端)转换为网络字节序(大端)

        3. 参数

                hostshort:本地端口号

        4. 返回值

                返回网络字节序端口号

        

      uint16_t ntohs(uint16_t netshort);
      功能:
        将网络字节序(大端)转换为本地字节序(小端)

1.4 bind

        1. 定义

              int bind(int sockfd, const struct sockaddr *addr,
                        socklen_t addrlen);

        2. 功能

                将套接字与IP地址端口绑定在一起

        3. 参数

                sockfd:文件描述符 
                addr:结构体空间首地址 
                addrlen:信息的长度

        4. 返回值

                成功返回0 
                失败返回-1 

        5. 注意

1.5 connect

        1. 定义

                  int connect(int sockfd, const struct sockaddr *addr,
                           socklen_t addrlen);

        2. 功能

                    向接收端发送三次握手链接请求

        3. 参数

                    sockfd:文件描述符
                    addr:接收方地址空间首地址
                    addrlen:接收方地址的大小

        4. 返回值

                    成功返回0 
                    失败返回-1 

        5. 注意

1.6 listen

        1. 定义

                  int listen(int sockfd, int backlog);

        2. 功能

                    监听链接请求

        3. 参数

                    sockfd:文件描述符
                    backlog:允许最多等待链接的个数

        4. 返回值

                    成功返回0 
                    失败返回-1 

        5. 注意

1.7 accept(返回通信套接字)

        1. 定义

                  int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

        2. 功能

                    处理等待队列中第一个链接

        3. 参数

                    sockfd:文件描述符 
                    addr:存放链接对方地址信息空间首地址
                    addrlen:想要接收地址大小变量空间首地址

        4. 返回值

                    成功返回与发送端建立的新文件描述符(通信套接字)
                    失败返回-1 

        5. 注意

1.8 send (发的太块会阻塞)

        1. 定义

                  ssize_t send(int sockfd, const void *buf, size_t len, int flags);

        2. 功能

                    发送数据

        3. 参数

                    sockfd:文件描述符
                    buf:存放数据空间首地址
                    len:发送数据长度
                    flags:属性 默认为0 

        4. 返回值

                    成功返回发送字节数
                    失败返回-1 

        5. 注意

1.9 recv

        1. 定义

                  ssize_t recv(int sockfd, void *buf, size_t len, int flags);

        2. 功能

                    接收数据

        3. 参数

                    sockfd:文件描述符
                    buf:存放数据空间首地址 
                    len:最多接收数据大小
                    flags:属性 默认为0 

        4. 返回值

                    成功返回实际接收字节数
                    失败返回-1 
                    对方关闭套接字返回0 

        5. 注意

2. TCP示例程序

2.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.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)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 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)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 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;
}

2.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)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 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)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 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;
}

3. TCP机制

    1.序列号:发送字节内容在缓存区中的编号(要发送字节的编号)
    2.确认号:收到字节内容的编号(只有ACK为1时才有确认号)
        本次发送数据序列号为上次收到ack数据包的确认号
        本次确认号为上次收到数据的序列号+实际收到数据长度

4. TCP特点

    1.实现机制复杂
    2.占用资源开销大
    3.安全、可靠、可控
    4.面向连接传输方式

相关推荐

  1. 嵌入学习——网络编程TCP)——day31

    2024-06-16 14:36:02       9 阅读

最近更新

  1. js list to tree

    2024-06-16 14:36:02       1 阅读
  2. 02更新用户在线状态

    2024-06-16 14:36:02       1 阅读
  3. CSS魔法:link与@import的秘密较量

    2024-06-16 14:36:02       1 阅读
  4. 第12章:软件系统分析与设计

    2024-06-16 14:36:02       1 阅读
  5. Rust入门实战 编写Minecraft启动器#2建立资源模型

    2024-06-16 14:36:02       1 阅读
  6. three.js利用着色器实现波浪效果

    2024-06-16 14:36:02       1 阅读
  7. Python pdfplumber库:轻松解析PDF文件

    2024-06-16 14:36:02       1 阅读

热门阅读

  1. 【名词解释】Unity中的3D物理系统:碰撞体

    2024-06-16 14:36:02       9 阅读
  2. 查找——顺序查找和折半查找

    2024-06-16 14:36:02       8 阅读
  3. LeetCode题练习与总结:最长连续序列--128

    2024-06-16 14:36:02       11 阅读
  4. 前端 CSS 经典:好用的 CSS 选择器

    2024-06-16 14:36:02       13 阅读
  5. 免费外链网站大全,助力新站收录加速

    2024-06-16 14:36:02       8 阅读
  6. (60)MOS管专题--->(15)MOS场效应管

    2024-06-16 14:36:02       15 阅读
  7. 25.梯度消失和梯度爆炸

    2024-06-16 14:36:02       9 阅读
  8. yocto根文件系统如何配置静态IP地址

    2024-06-16 14:36:02       9 阅读
  9. web前端网上私活:探索、挑战与成长的独特之旅

    2024-06-16 14:36:02       9 阅读