Linux系统编程-DAY10(TCP操作)

发布于:2025-06-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、网络模型
1、服务器/客户端模型
(1)C/S:client server

(2)B/S:browser server

(3)P2P:peer to peer

2、C/S与B/S区别
(1)客户端不同:B/S模型中B为通用客户端,C/S模型中C为专用客户端;

(2)使用协议不同:

                B/S模型:用HTTP(超文本传输协议)

                C/S模型:自定义(自由度更高)

(3)功能角度:

                B/S模型:功能设计相对简单

                C/S模型:功能设计复杂

(4)资源角度:

                B/S模型:所有资源都由服务端发过来

                C/S模型:资源可认为是本地的(事先下好的)

3、P2P模型
下载软件、文件、视频可用(既是客户端也干了服务器的事(提供服务))

二、TCP(传输控制协议)
(一)TCP概述
TCP 是 TCPIIP 体系中非常复杂的一个协议。下面介绍TCP最主要的特点。

(1)TCP是面向连接的运输层协议。

(2)每一条 TCP连接只能有两个端点(endpoint),每一条 TCP连接只能是点对点的(一对一)。

(3)TCP提供可靠交付的服务。也就是说,通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达。

(4)TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。

(5)面向字节流。

注:三次握手的第一次封装在accept()函数和connect()函数中;

        四次挥手双方都调用close()函数,双方都把close()函数走完才认为四次挥手结束。

(二)TCP的特征(面问高频问题)
1、有链接
先确定链路,建立连接(在整个通信过程中一直保持,除非双方断开连接)

三次握手:建立连接;四次挥手:断开连接

 1-3三次握手(建立连接),4-7处理数据(收发),7-10四次挥手(断开连接)

第8步:ACK1022(第一种情况:之前请求的数据未发完,先应答,说明收到断开,套接字进入半连接状态;第二种情况:双方数据量没那么大,服务器没什么要发的,第八步是有可能被省略的)

SYN:请求连接

ACK:应答

编号:协商双方起始编号

2、可靠传输(因为有链接)
(1)应答机制

(2)超时重传

3、TCP流式套接字
(1)流式套接字:全双工(既能收也能发)(因为是双缓冲区(发送缓冲区和接收缓冲区))

(2)流式套接字示意图:

第一种:recv(100)一把收完(拿走)

第二种:recv(3)一个一个取,不会丢

(3)流式套接字(两个)特性:

        数据本身是连续的(无边界);

        有顺序的(数据会有序到达)(发和收的次序可不对应)

4、扩展:黏包问题
(1)(双方发数据事先未约定好)数据发送过去接收方没办法正常按发送方那边拆开包;

(2)原因:数据无边界;

(3)解决方案

        a.设计分隔符(加分隔符(自己设定))

        b.固定大小(典型代表:struct(结构体))

        c.自定义协议

eg:AA CC 04 1 2 3 4 CRC1 CRC2 BB DD

        AA CC:开头标志

        BB DD:结尾标志

        04:标识数据长度(自定义)

        1 2 3 4:正文4个字节

三、编程步骤
1.服务端:socket()---> bind()--->listen()--->accept()--->recv()--->send()--->close()
2.客户端:socket()--->connect()--->send()--->recv()--->send()

recv 的返回值 >0 :实际收到的字节数
                       =0 :断开
                       <0 :出错
调用recv会阻塞,send写满的时候会阻塞
3.conn是通信套接字

四、代码与例题
                                                        TCP ser.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

typedef struct sockaddr *(SA);
int	main(int argc, char **argv)
{
    int listfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == listfd)
    {
        perror("socket");
        return 1;
    }

    struct sockaddr_in ser, cli;
    bzero(&ser, sizeof(ser));
    bzero(&cli, sizeof(cli));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("192.168.0.199");

    int ret = bind(listfd, (SA)&ser, sizeof(ser));
    if(-1 == ret)
    {
        perror("bind");
        return 1;
    }

    listen(listfd, 3);
    socklen_t len = sizeof(cli);

    int conn = accept(listfd, (SA)&cli, &len);
    if(-1 == conn)
    {
        perror("conn");
        return 1;
    }

    while(1)
    {
        char buf[256] = {0};
        ret = recv(conn, buf, sizeof(buf), 0);
        if(ret <= 0)
        {
            break;
        }
        printf("cli : %s\n", buf);
        time_t tm;
        time(&tm);
        struct tm *info = localtime(&tm);
        sprintf(buf, "%s %d:%d:%d\n",buf, info->tm_hour
        , info->tm_min, info->tm_sec);
        send(conn, buf, strlen(buf), 0);
    }
    
    close(conn);
    close(listfd);
    return 0;
}

                                                                TCP cli.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

typedef struct sockaddr *(SA);
int	main(int argc, char **argv)
{
    int conn = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == conn)
    {
        perror("socket");
        return 1;
    }

    struct sockaddr_in ser, cli;
    bzero(&ser, sizeof(ser));
    bzero(&cli, sizeof(cli));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(50000);
    ser.sin_addr.s_addr = inet_addr("192.168.0.119");
    int ret = connect(conn, (SA)&ser, sizeof(ser));
    if(-1 == ret)
    {
        perror("connect");
        return 1;
    }

    while(1)
    {
        char buf[256] = {0};
        strcpy(buf, "cyy ");
        send(conn, buf, strlen(buf), 0);

        ret = recv(conn, buf, sizeof(buf), 0);
        if(ret <= 0)
        {
            break;
        }
        printf("ser: %s", buf);
        fflush(stdout);
        sleep(1);
    }
    
    close(conn);
    return 0;
}