Question: What does the code below output? Why?
 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);
Complete code 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;
}
Complete code: 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;
}
output
 server start success
client: 4
Receive: ABC

tips

  • send buffer

    • The data first enters the send buffer, and then is sent to the remote host by the operating system
  • receive buffer

    • The remote data is accepted by the operating system and put into the receive buffer
    • Afterwards the application reads the data from the receive buffer

image.png

"Problems" in TCP Application Programming

The receiver of the data has no way of knowing how the data was sent

image.png

The receiver has no way of knowing that "ABC" was sent separately!

Expectations in Network Programming

  • Send a complete message at a time, receive a complete message at a time
  • No message sticking even if there are multiple messages in the receive buffer
  • The message covers information such as data type and data length

Application layer protocol design

  • What is an agreement?

    • A protocol is a set of rules , standards or predetermined sets established by both parties for data exchange
  • The role of protocols in data transmission

    • Both communication parties can correctly send and receive data according to the agreement
    • The communication parties can explain the meaning of the data according to the agreement

Protocol Design Example

  • Goal: Design a protocol that can be used for data transfer
  • The complete message contains

    • Data header: data type (ie: data area usage, fixed length)
    • Data length: data area length (fixed length)
    • Data area: byte data (variable length area)

image.png

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

Programming experiment: application layer protocol design and implementation

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;
}
output
 0000000001000300010000004100000000020003000100000042000000000300
03000100000043

Thinking: How to encapsulate protocol details (only the relational message itself) at the code layer?

TianSong
737 声望139 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧