问题:上面的代码输入什么?为什么?
printf("connect success\n");send(sock, "A", 1, 0);send(sock, "B", 1, 0);send(sock, "C", 1, 0);close(sock);
do {    r = recv(client, buf, sizeof(buf), 0);    if (r > 0) {        printf("Recv: %s\n", buf);    }}while (1);close(client);
残缺代码 client.c
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){    int sock = 0;    struct sockaddr_in addr = {0};    int len = 0;    char buf[128] = {0};    char input[32] = {0};    int r = 0;    sock = socket(PF_INET, SOCK_STREAM, 0);    if (sock == -1) {        printf("socket error\n");        return -1;    }    addr.sin_family = AF_INET;    addr.sin_addr.s_addr = inet_addr("127.0.0.1");    addr.sin_port = htons(8888);    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {        printf("connect error\n");        return -1;    }    printf("connect success\n");    send(sock, "A", 1, 0);    send(sock, "B", 1, 0);    send(sock, "C", 1, 0);    close(sock);    return 0;}
残缺代码:server.c
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){    int server = 0;    struct sockaddr_in saddr = {0};    int client = 0;    struct sockaddr_in caddr = {0};    socklen_t asize = 0;    int len = 0;    char buf[32] = {0};    int r = 0;    server = socket(PF_INET, SOCK_STREAM, 0);    if (server == -1) {        printf("server socket error\n");        return -1;    }    saddr.sin_family = AF_INET;    saddr.sin_addr.s_addr = htonl(INADDR_ANY);    saddr.sin_port = htons(8888);    if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {        printf("server bind error\n");        return -1;    }    if (listen(server, 1) == -1) {        printf("server listen error\n");        return -1;    }    printf("server start success\n");    while (1) {        asize = sizeof(caddr);        client = accept(server, (struct sockaddr*)&caddr, &asize);        if (client == -1) {            printf("client accept error\n");            return -1;        }        printf("client: %d\n", client);        do {            r = recv(client, buf, sizeof(buf), 0);            if (r > 0) {                printf("Receive: %s\n", buf);              }         } while (r > 0);        close(client);    }    close(server);    return 0;}
输入
server start successclient: 4Receive: ABC

小常识

  • 发送缓冲区

    • 数据先进入发送缓冲区,之后由操作系统送往远端主机
  • 接收缓冲区

    • 远端数据被操作系统承受后放入接收缓冲区
    • 之后应用程序从接收缓冲区读取数据

TCP 利用编程中的 “问题”

数据接收端无奈晓得数据的发送形式

接收端无奈晓得 "ABC" 是离开发送的!

网络编程中的冀望

  • 每次发送一条残缺的消息,每次接管一条残缺的音讯
  • 即便接收缓冲区中有多条音讯,也不会呈现音讯粘连
  • 音讯中涵盖了数据类型和数据长度等信息

应用层协定设计

  • 什么是协定?

    • 协定是通信单方为数据交换而建设的规定规范预约的汇合
  • 协定对数据传输的作用

    • 通信单方依据协定可能正确收发数据
    • 通信单方依据协定可能解释数据的意义

协定设计示例

  • 指标:设计可用于数据传输的协定
  • 残缺音讯蕴含

    • 数据头:数据类型(即:数据区用处,固定长度)
    • 数据长度:数据区长度(固定长度)
    • 数据区:字节数据(变长区域)

上图可知:音讯至多 12 个字节(音讯头 + 数据长度)通过计算音讯的总长度,可能避开数据粘连的问题
typedef struct {    unsigned short type;    unsigned short cmd;    unsigned short index;    unsigned short total;    unsigned int length;    unsigned char payload[];  // 柔性数组}Message;

编程试验:应用层协定设计与实现

client.c
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include "message.h"int main(){    int sock = 0;    struct sockaddr_in addr = {0};    int len = 0;    char buf[128] = {0};    char input[32] = {0};    int r = 0;    Message *pm = NULL;    sock = socket(PF_INET, SOCK_STREAM, 0);    if (sock == -1) {        printf("socket error\n");        return -1;    }    addr.sin_family = AF_INET;    addr.sin_addr.s_addr = inet_addr("127.0.0.1");    addr.sin_port = htons(8888);    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {        printf("connect error\n");        return -1;    }    printf("connect success\n");    pm = Message_New(0, 0, 1, 3, "A", 1);    send(sock, pm, sizeof(Message) + 1, 0);    pm = Message_New(0, 0, 2, 3, "B", 1);    send(sock, pm, sizeof(Message) + 1, 0);    pm = Message_New(0, 0, 3, 3, "C", 1);    send(sock, pm, sizeof(Message) + 1, 0);    close(sock);    return 0;}
server.c
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>int main(){    int server = 0;    struct sockaddr_in saddr = {0};    int client = 0;    struct sockaddr_in caddr = {0};    socklen_t asize = 0;    int len = 0;    char buf[32] = {0};    int r = 0;    server = socket(PF_INET, SOCK_STREAM, 0);    if (server == -1) {        printf("server socket error\n");        return -1;    }    saddr.sin_family = AF_INET;    saddr.sin_addr.s_addr = htonl(INADDR_ANY);    saddr.sin_port = htons(8888);    if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {        printf("server bind error\n");        return -1;    }    if (listen(server, 1) == -1) {        printf("server listen error\n");        return -1;    }    printf("server start success\n");    while (1) {        asize = sizeof(caddr);        client = accept(server, (struct sockaddr*)&caddr, &asize);        if (client == -1) {            printf("client accept error\n");            return -1;        }        printf("client: %d\n", client);        do {            r = recv(client, buf, sizeof(buf), 0);            if (r > 0) {                int i = 0;                for (i=0; i<r; ++i) {                    printf("%02x", buf[i]);                }                printf("\n");            }         } while (r > 0);        close(client);    }    close(server);    return 0;}
输入
000000000100030001000000410000000002000300010000004200000000030003000100000043

思考:如何在代码层封装协定细节(仅关系音讯自身)?