嵌入式学习——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);

  1. 功能

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

  1. 参数

domain:AF_INET IPv4协议族

type:SOCK_STREAM 流式套接字 tcp传输协议

SOCK_DGRAM 数据报套接字 udp传输协议

SOCK_RAW 原始套接字

protocol:

默认为0

  1. 返回值

成功返回套接字新文件描述符

失败返回-1

  1. 注意

1.2 inet_addr

  1. 定义

in_addr_t inet_addr(const char *cp);

  1. 功能

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

  1. 参数

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

  1. 返回值

成功返回二进制IP地址

  1. 注意

1.3 htons

  1. 定义

uint16_t htons(uint16_t hostshort);

  1. 功能

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

  1. 参数

hostshort:本地端口号

  1. 返回值

返回网络字节序端口号

uint16_t ntohs(uint16_t netshort);

功能:

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

1.4 bind

  1. 定义

int bind(int sockfd, const struct sockaddr *addr,

socklen_t addrlen);

  1. 功能

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

  1. 参数

sockfd:文件描述符

addr:结构体空间首地址

addrlen:信息的长度

  1. 返回值

成功返回0

失败返回-1

  1. 注意

1.5 connect

  1. 定义

int connect(int sockfd, const struct sockaddr *addr,

socklen_t addrlen);

  1. 功能

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

  1. 参数

sockfd:文件描述符

addr:接收方地址空间首地址

addrlen:接收方地址的大小

  1. 返回值

成功返回0

失败返回-1

  1. 注意

1.6 listen

  1. 定义

int listen(int sockfd, int backlog);

  1. 功能

监听链接请求

  1. 参数

sockfd:文件描述符

backlog:允许最多等待链接的个数

  1. 返回值

成功返回0

失败返回-1

  1. 注意

1.7 accept(返回通信套接字)

  1. 定义

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

  1. 功能

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

  1. 参数

sockfd:文件描述符

addr:存放链接对方地址信息空间首地址

addrlen:想要接收地址大小变量空间首地址

  1. 返回值

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

失败返回-1

  1. 注意

1.8 send (发的太块会阻塞)

  1. 定义

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

  1. 功能

发送数据

  1. 参数

sockfd:文件描述符

buf:存放数据空间首地址

len:发送数据长度

flags:属性 默认为0

  1. 返回值

成功返回发送字节数

失败返回-1

  1. 注意

1.9 recv

  1. 定义

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

  1. 功能

接收数据

  1. 参数

sockfd:文件描述符

buf:存放数据空间首地址

len:最多接收数据大小

flags:属性 默认为0

  1. 返回值

成功返回实际接收字节数

失败返回-1

对方关闭套接字返回0

  1. 注意

  2. TCP示例程序

2.1 TCP单向通信

(1)头文件

cpp 复制代码
#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

cpp 复制代码
all:send recv

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

(3)recv.c

cpp 复制代码
#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

cpp 复制代码
#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)头文件

cpp 复制代码
#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

cpp 复制代码
all:send recv

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

(3)recv.c

cpp 复制代码
#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

cpp 复制代码
#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)头文件

cpp 复制代码
#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

cpp 复制代码
all:send recv

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

(3)recv.c

cpp 复制代码
#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

cpp 复制代码
#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;
}
  1. TCP机制

1.序列号:发送字节内容在缓存区中的编号(要发送字节的编号)

2.确认号:收到字节内容的编号(只有ACK为1时才有确认号)

本次发送数据序列号为上次收到ack数据包的确认号

本次确认号为上次收到数据的序列号+实际收到数据长度

  1. TCP特点

1.实现机制复杂

2.占用资源开销大

3.安全、可靠、可控

4.面向连接传输方式

相关推荐
Orangejuz4 分钟前
go 学习 之 HTTP微服务示例
学习·http·golang
bitcsljl6 分钟前
Linux系统中卸载GitLab
linux·运维·gitlab
精选软件库27 分钟前
3个让你爽到爆炸的学习工具
学习
想胖的壮壮28 分钟前
python中的原子操作简介
开发语言·python
oDrake28 分钟前
Openstack制作Rhel9,使用IOS镜像制作
linux·openstack·虚拟化·rhel-9.3
爱吃香菜¹30 分钟前
深入理解【 String类】
java·开发语言
六月的雨__33 分钟前
跑腿平台小程序的设计
java·sql·学习·小程序
Kazefuku39 分钟前
sublime如何运行Html文件?
笔记·学习·sublime text
LeoLei806044 分钟前
新特性之C++17
开发语言·c++
Ops菜鸟(Xu JieHao)1 小时前
Linux开源监控工具netdata
运维·服务器·监控·云监控·netdata·监控神器