基于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

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

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include           /* See NOTES */
#include 
#include 
#include  
#include 
#include 
#include 
#include 
#include 

#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!
");
        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!
");
        return -1;
    }

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

    confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
    if (-1 == confd)
    {
        perror("accept error!
");
        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!
");
            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!
");
        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!
");
        return -1;        
    }

    while (1)
    {
        char buf[256] = {"supercarrydoinb"};
        ret_send = send(confd, buf, strlen(buf), 0);
        if (-1 == ret_connect)
        {
            perror("send error!
");
            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 
#include 
#include 
#include 
#include 
#include 
#include 
#include           /* See NOTES */
#include 
#include 
#include  
#include 
#include 
#include 
#include 
#include 

#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!
");
        }
        printf("from recv: %s
", 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] = '
#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!
");
}
printf("from recv: %s
", 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!
");
}
}
}
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!
");
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!
");
return -1;
}
#if 0
ret_recv = recv(confd, buf, sizeof(buf), 0);
if (-1 == ret_recv)
{
perror("recv error!
");
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;
}
'; ret_send= send(confd, buf, strlen(buf), 0); if (-1 == ret_send) { perror("send error! "); } } } 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! "); 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! "); return -1; } #if 0 ret_recv = recv(confd, buf, sizeof(buf), 0); if (-1 == ret_recv) { perror("recv error! "); 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!
");
        }
        printf("from send: %s
", 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] = '
#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!
");
}
printf("from send: %s
", 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!
");
}
}
}
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!
");
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!
");
return -1;
}
ret_listen = listen(listfd, 3);
if (-1 == ret_listen)
{
perror("listen error!
");
return -1;        
}
confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
if (-1 == confd)
{
perror("accept error!
");
return -1;         
}
#if 0
ret_recv = recv(confd, buf, sizeof(buf), 0);
if (-1 == ret_recv)
{
perror("recv error!
");
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;
}
'; ret_send = send(confd, buf, strlen(buf), 0); if (-1 == ret_send) { perror("send error! "); } } } 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! "); 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! "); return -1; } ret_listen = listen(listfd, 3); if (-1 == ret_listen) { perror("listen error! "); return -1; } confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen); if (-1 == confd) { perror("accept error! "); return -1; } #if 0 ret_recv = recv(confd, buf, sizeof(buf), 0); if (-1 == ret_recv) { perror("recv error! "); 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include           /* See NOTES */
#include 
#include 
#include  
#include 
#include 
#include 
#include 
#include 

#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!
");
        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!
");
        return -1;
    }

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

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

    ret_stat = stat("./1.png", &st);
    if (-1 == ret_stat)
    {
        perror("stat error!
");
        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!
");
        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!
");
        return -1;
    }


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

    confd = accept(listfd, (struct sockaddr *)&sendaddr, &addrlen);
    if (-1 == confd)
    {
        perror("accept error!
");
        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
");
            return -1;
        }

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

            flag = 1;
            total = msg.total;
        }

        write(openfd, msg.buf, msg.rd_ret);
        current_size += msg.rd_ret;
        printf("%d / %d
", 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.面向连接传输方式

本站无任何商业行为
个人在线分享 » 嵌入式学习——Linux高级编程复习(TCP编程)——day44
E-->