TCP/IP编程入门-案例学习

前言

     从作为一名数据分析从业者,一直不太了解后台开发岗位所使用的各种网络编程方法,于是也就老想闹明白,这个东西究竟是咋玩的? 本文试图通过一个小案例,来管窥下这个领域的编程套路。参考的书籍主要是《TCP/IP网络编程》(尹圣丽 著 金国哲 译)。

我们知道,网络编程主要就是实现服务端与客户端的通信,那么就涉及到一系列通信过程的协议,也就是双方要商量好有一套共同的语境。这就又跳到计算机网络知识中的OSI网络体系模型,共分了7层(具体可参考相关书籍)。实际应用中,可简化理解为4层,从上往下为 应用层、传输层、网络层、链路层。TCP就是传输层中的一种协议,是一种基于连接的,比较可靠的,不会发生数据丢失的协议,相对应的是UDP协议。 IP对应的是网络层,这其中也有一堆不同的协议,如IPv4, IPv6等。

在编写网络通信过程时,最重要的几个环节如下:

对于服务端: 建立套接字、绑定网络地址、监听、接受、读取/写入、关闭连接

对于客户端:建立套接字、请求连接、读取/写入、关闭连接

      

案例问题

    1. 写一个server,根据客户端传入的两个数值,进行数学计算,如加减乘除。

    2. 写一个client,向server传入若两个数值,以及所需的计算方法


练习过程

以下练习过程在一台笔记本上完成,server, client部署在同一个机器上。编程语言为C。

服务端代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUF_SIZE 1024

long doMathWork(char op, int num1, int num2);

int main(int argc, char* argv[]){

    int server_sock, client_sock;
    char msg[BUF_SIZE];
    size_t str_len;
    //声明网络地址的结构体
    struct sockaddr_in server_addr;  //服务端网络地址
    struct sockaddr_in client_addr;  //客户端网络地址
    int i;

    socklen_t client_addr_size;

    //声明计算类型, 以及两个数值变量
    char op;
    int num1, num2;
    long result;

    if(argc != 2){
        printf("Usage: %s  \n", argv[0]);
        exit(1);
    }

    char* port = argv[1];

    //第1步, 建立服务端套接字
    server_sock = socket(PF_INET /*IPv4*/,SOCK_STREAM /*TCP*/,0);
    if(server_sock == -1){
        fputs("socket error", stderr);
        fputc('\n', stderr);
        exit(-1);
    }

    //第2步, 绑定网络地址
    //定义网络地址结构体
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;  //IPv4地址族
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(port));

    if(bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
        fputs("bind error", stderr);
        fputc('\n', stderr);
        exit(-2);
    }

    //第3步, 建立监听
    if(listen(server_sock, 1) == -1){
        fputs("listen error", stderr);
        fputc('\n', stderr);
        exit(-3);
    }

    //第4步, 接受访问
    client_addr_size = sizeof(client_addr);
    client_sock = accept(server_sock, (struct sockaddr*)&client_sock, &client_addr_size);
    if(client_sock == -1){
        fputs("accept error", stderr);
        fputc('\n', stderr);
        exit(-4);
    }else{
        printf("Connected to client........\n");
    }

    //第5步, 传输内容
    //首先接收一个计算类型, 如加减乘除
    read(client_sock, msg, BUF_SIZE-1);
    msg[strlen(msg)-1] = 0;
    op = msg[0];
    printf("op: %c \n", op);

    read(client_sock, msg, BUF_SIZE-1);
    num1 = atoi(msg);
    printf("num1: %d \n", num1);

    read(client_sock, msg, BUF_SIZE-1);
    num2 = atoi(msg);
    printf("num2: %d \n", num2);

    result = doMathWork(op, num1, num2);
    write(client_sock, (char*)&result, sizeof(result));

    //第6步, 关闭连接
    close(client_sock);
    close(server_sock);

    return 0;
}


long doMathWork(char op, int num1, int num2){
    long result = 0L;
    switch(op){
        case '+':
            result = num1 + num2;
            break;
        case '-':
            result = num1 - num2;
            break;
        case '*':
            result = num1 * num2;
            break;
        case '/':
            if(num2 == 0){
                fputs("cannot divide zero",stderr);
                fputc('\n',stderr);
                exit(-1);
            }
            result = num1 / num2;
            ;
        default:
            printf("You have input %c \n", op);
            fputs("only allow input: + - * / \n", stderr);
            break;
    }
    printf("result: %li \n" , result);
    return result;
}

客户端代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUF_SIZE 1024

//注意到服务端程序中,有多个地方使用类似的逻辑来处理函数返回值,故可定义一个公用的函数
void error_msg(char* message);

int main(int argc, char* argv[]){

    int client_sock;
    struct sockaddr_in server_addr;
    char* message[BUF_SIZE];

    int str_len;
    long result;

    char* ip;
    char* port;
    if(argc != 3){
        printf("Usage: %s  " , argv[0]);
        exit(-1);
    }
    ip = argv[1];
    port = argv[2];

    //第1步, 建立套接字
    client_sock = socket(PF_INET,SOCK_STREAM,0);
    if(client_sock == -1) error_msg("socket() error");

    //第2步, 连接服务端套接字
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(ip);
    server_addr.sin_port = htons(atoi(port));

    if(connect(client_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
        error_msg("connect() error");
    }else{
        puts("Connection Created ............\n");
    }

    //第3步, 通信内容
    printf("Input a kind of opeator(+ - * /): ");
    fgets((char *) message, BUF_SIZE, stdin);
    write(client_sock, message, strlen((const char *) message));

    printf("Input the first number: ");
    fgets((char *) message,BUF_SIZE, stdin);
    write(client_sock, message, strlen((const char *) message));

    printf("Input the second number: ");
    fgets((char *) message,BUF_SIZE, stdin);
    write(client_sock, message, strlen((const char *) message));

    read(client_sock, &result, 4);
    printf("math result: %li \n", result);

    //第4步, 关闭连接
    close(client_sock);
    return 0;
}

void error_msg(char* message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

运行结果

       服务端:

TCP/IP编程入门-案例学习_第1张图片

              

客户端:

TCP/IP编程入门-案例学习_第2张图片

你可能感兴趣的:(菜鸟练习本)