【Socket】简单的回声服务器实现

3

网络通信

Socket通信的3要素

  1. 通信的目的地址
  2. 使用的端口号
  3. 使用的传输层协议(如TCP、UDP)

Socket通信模型

image-20220502174714890

简单的回声服务器实现

服务端

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>

#define SERVER_PORT 666

int main(void){

    int sock;//信箱

    struct sockaddr_in server_addr;

    //创建信箱
    sock = socket(AF_INET,SOCK_STREAM,0);

    //清空标签
    bzero(&server_addr,sizeof(server_addr));    
    //写上地址和端口号
    server_addr.sin_family = AF_INET;       //选择协议族ipv4
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//监听本地所有IP地址-几个网卡就有几个IP地址
    server_addr.sin_port = htons(SERVER_PORT);  //绑定端口号

    //实现标签贴到收信的信箱上
    bind(sock,(struct sockaddr*)&server_addr,sizeof(server_addr));

    //邮箱一次性只能接收128封信件
    listen(sock,128);

    printf("等待客户端链接\n");

    int done = 1;

    while(done){
        struct sockaddr_in client;

        int client_socket;      
        int len;

        char client_ip[64];

        char buf[256];

        socklen_t client_addr_len;

        client_addr_len = sizeof(client);   

        client_socket = accept(sock,(struct sockaddr*)&client,&client_addr_len);

        printf("客户端地址:%s\t端口:%d\n",inet_ntop(AF_INET,&client.sin_addr.s_addr,client_ip,sizeof(client_ip)),ntohs(client.sin_port));

        //读取数据
        len = read(client_socket,buf,sizeof(buf)-1);

        buf[len] = '\n';//read读过来的数据不会自动加字符串结束符

        printf("收到[%d]:%s\n",len,buf);

        len = write(client_socket,buf,len);//发回去

        printf("写完,len:%d",len);

        close(client_socket);
    }

    return 0;
}

可以使用telnet来模拟客户端链接服务器。例如:

image-20220502224213022

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define SERVER_PORT 666
#define SERVER_IP "127.0.0.1"

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

    int sockfd;
    char* message;

    struct sockaddr_in servaddr;

    int n;

    char buf[64];

    //echo_client "xxxx"   ——所以判断是否为2
    if (argc != 2) {
        fputs("Usage: ./echo_client message \n",stderr);
        exit(1);
    }

    message = argv[1];
    printf("message: %s\n",message);

    sockfd = socket(AF_INET,SOCK_STREAM,0);

    memset(&servaddr,'\0',sizeof(struct sockaddr_in));

    servaddr.sin_family = AF_INET;

    //inet_pton(AF_INET,SERVER_IP,&servaddr.sin_addr);
    inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr);
    servaddr.sin_port = htons(SERVER_PORT); //转换为网络字节序

    connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

    write(sockfd,message,strlen(message));

    n = read(sockfd, buf, sizeof(buf)-1);

    if (n > 0) {
        buf[n] = '\n';
        printf("receive: %s\n",buf);
    } else {
        perror("error!");
    }

    printf("finished!\n");
    close(sockfd);

    return 0;
}

测试

image-20220503000726910