嵌入式学习——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.面向连接传输方式

相关推荐
----云烟----1 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024061 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic1 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it1 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康1 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神2 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
搬砖的小码农_Sky2 小时前
C语言:数组
c语言·数据结构
宅小海2 小时前
scala String
大数据·开发语言·scala
朝九晚五ฺ2 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
qq_327342732 小时前
Java实现离线身份证号码OCR识别
java·开发语言