网络基础——应用层

协议是一种“约定”。socket  api的接口在读写数据时,都是按字符串的方式来发送接收的。如果我们要传输一些“结构化的数据”,就应该先将结构化的数据转化为字符串风格的数据,这个过程称为“数据序列化”。相同的,当接收方将数据从网络中获取到时,需要将字符串风格的数据再转化为结构化的数据,这个过程就成为“数据反序列化”。

例如,我们需要实现一个服务器版本的加法器,就需要客户端把要计算的两个加数发送过去,然后由服务器进行计算,最后再把结果返回给客户端。

我们可以约定一个方案:

    1.定义结构体来表示我们需要交互的信息;

    2.发送数据时将这个结构体按照一个规则转换为字符串,接收到数据时再按照相同的规则把字符串转化回结构体。这个过程就是“序列化”和“反序列化”的过程。

comm.h:
#pragma once
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<sys/types.h>

#define MAX 128

typedef struct{
    int x;
    int y;
}request_t;


typedef struct{
    int res;
}response_t;

server.c:
#include"comm.h" 
  
#define MAX 128  
  
typedef struct {   
    int sock;  
    char ip[24];  
    int port;  
}net_info_t;  
  
int Startup(char* ip,int port){  
    int sock = socket(AF_INET,SOCK_STREAM,0);  
    if(sock < 0){  
            printf("socket error!\n");  
            exit(2);  
        }  
    struct sockaddr_in local;  
    local.sin_family = AF_INET;  
    local.sin_addr.s_addr = inet_addr(ip);  
    local.sin_port = htons(port);  
  
    if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){  
            printf("bind error!\n");  
            exit(3);  
        }  
      
    if(listen(sock,5) < 0){  
            printf("listen error!\n");  
            exit(4);  
        }  
  
    return sock;  
}  
  
void service(int sock,char* ip,int port){ 
    while(1){
   request_t r;
   read(sock,&r,sizeof(r));
   response_t rp;
   rp.res = r.x + r.y;
   write(sock,&rp,sizeof(rp));
    }
}
              
  
void* thread_service(void* arg){  
    net_info_t* p = (net_info_t*)arg;  
    service(p->sock,p->ip,p->port);  
    close(p->sock);  
    free(p); 
}  
  
int main(int argc,char* argv[]){  
    if(argc != 3){  
            printf("Usage:%s [ip] [port]\n",argv[0]);  
            return 1;  
        }  
    int listen_sock = Startup(argv[1],atoi(argv[2]));  
      
    struct sockaddr_in peer;  
    char ipBuf[24];  
    for(;;){  
            ipBuf[0] = 0;  
            socklen_t len = sizeof(peer);  
            int new_sock = accept(listen_sock,(struct sockaddr*)&peer,&len);  
            if(new_sock < 0){  
                        printf("accept error!\n");  
                        continue;  
                    }  
            inet_ntop(AF_INET,(const void*)&peer.sin_addr,ipBuf,sizeof(ipBuf));  
            int p = ntohs(peer.sin_port);  
            printf("get a new connect,[%s:%d]\n",ipBuf,p);  
      
            net_info_t *info = (net_info_t*)malloc(sizeof(net_info_t));  
            if(info == NULL){  
                        perror("malloc");  
                        close(new_sock);  
                        continue;  
                    }  
            info->sock = new_sock;  
            strcpy(info->ip,ipBuf);  
            info->port = p;  
      
            pthread_t tid;  
            pthread_create(&tid,NULL,thread_service,(void*)info);  
            pthread_detach(tid);  
        }  
    return 0;  
}

client.c:
#include"comm.h"
  
int main(int argc,char* argv[]){  
    if(argc != 3){  
            printf("Usage:%s [ip] [port]\n",argv[0]);  
            return 1;  
        }  
    int sock = socket(AF_INET,SOCK_STREAM,0);  
    if(sock < 0){  
            printf("socket error!\n");  
            return 2;  
        }  
  
    struct sockaddr_in server;  
    server.sin_family = AF_INET;  
    server.sin_port = htons(atoi(argv[2]));  
    server.sin_addr.s_addr = inet_addr(argv[1]);  
  
    if(connect(sock,(struct sockaddr*)&server,sizeof(server)) < 0){  
            printf("connect error!\n");  
            return 3;  
        }  
  
    char buf[MAX];  
    int x,y;
    request_t r;
    while(1){  
            printf("please Enter# ");  
            scanf("%d%d",&r.x,&r.y);
            write(sock,&r,sizeof(r));
            response_t rp;
            read(sock,&rp,sizeof(rp));
            printf("%d + %d = %d\n",r.x,r.y,rp.res);

        }  
    close(sock);  
    return 0;  
}

运行结果:

我们在一个终端上开启服务器端,在另外一个终端上开启客户端连接服务器,这时服务器端就会显示有新连接。从客户端发送需要进行加法运算的数据,服务器端经过运算,即可将结果显示到客户端的显示器上。

服务器端:

                    

客户端:

                

无论我们采用何种方案,只要保证一端发送时构造的数据在另一端能够正确的进行解析即可。这种约定就是应用层约定。




猜你喜欢

转载自blog.csdn.net/cecilia3333/article/details/80328827