SOCKET(一):基本轮子详解与入门

发布时间 2023-04-19 23:32:58作者: Aspirants

1.图解客户端与服务端交互流程

image

上图轮子详解

socket简单实践

服务端
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <fcntl.h>
#include <unistd.h>

unsigned short server_Port = 1234; // 服务器端口
const char *IP = "192.168.80.132"; // 服务器IP

/**字母转大写*/
void upper(char *buf)
{
    char *pointer = buf;
    while (*pointer != '\n')
    {
        if (*pointer >= 'a' && *pointer <= 'z')
            *pointer -= 32;
        pointer++;
    }
    return;
}

int main()
{
    //创建套接字
    int server_Socket = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_Addr;
    server_Addr.sin_family = AF_INET;
    server_Addr.sin_port = htons(server_Port);
    int flag = inet_aton(IP, &(server_Addr.sin_addr));
    if (!flag)
    {
        perror("IP transfer failed!\n");
    }

    //绑定服务器IP地址端口号
    bind(server_Socket, (struct sockaddr *)&server_Addr, sizeof(server_Addr));
    listen(server_Socket, 5);

    while (1)
    {

        printf("等待用户连接!\n");
        struct sockaddr_in client_Addr;
        int addrlen = sizeof(client_Addr);
        int conn_Socket = accept(server_Socket, (struct sockaddr *)&client_Addr, &addrlen);
        if (conn_Socket == -1)
        {
            perror("conn failed!\n");
        }

        //提取客户端信息
        char *client_Ip = inet_ntoa(client_Addr.sin_addr);
        unsigned short client_Port = ntohs(client_Addr.sin_port);
        printf("客户端: %s:%hu已连接!\n", client_Ip, client_Port);

        while (1)
        {

            char buf[100];
            memset(buf, '\0', 100);
            int count = read(conn_Socket, buf, 99);
            if (count == -1)
            {
                printf("客户端: %s:%hu连接故障!\n", client_Ip, client_Port);
            }
            else if (count == 0)
            {
                printf("客户端: %s:%hu断开连接!\n", client_Ip, client_Port);
                close(conn_Socket);
                break;
            }
            else
            {
                printf("客户端: %s:%hu消息:%s", client_Ip, client_Port, buf);
                upper(buf);
                write(conn_Socket, buf, 99);
            }
        }
    }
    
    return 0;
}
客户端
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <fcntl.h>
#include <unistd.h>

unsigned short server_Port = 1234; // 服务器端口
const char *IP = "192.168.80.132"; // 服务器IP
int main()
{
    // 创建套接字
    int client_Socket = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_Addr;
    server_Addr.sin_family = AF_INET;
    server_Addr.sin_port = htons(server_Port);
    int flag = inet_aton(IP, &(server_Addr.sin_addr));
    if (!flag)
    {
        perror("IP transfer failed!\n");
    }

    // 连接服务器
    flag = connect(client_Socket, (struct sockaddr *)&server_Addr, sizeof(server_Addr));
    if (flag == -1)
    {
        perror("conn failed!\n");
        return 0;
    }
    printf("成功连接服务端!\n");

    while (1)
    {
        // 终端输入
        printf("请输入消息:");
        char buf[100];
        fgets(buf, 99, stdin);

        // input end quit!
        if (strncmp(buf, "end", 3) == 0)
        {
            printf("用户退出!\n");
            close(client_Socket);
            break;
        }

        write(client_Socket, buf, 99);
        int count = read(client_Socket, buf, 99);

        if (count == -1)
        {
            printf("服务器连接故障!\n");
        }
        else if (count == 0)
        {
            printf("与服务器断开连接!\n");
            close(client_Socket);
            break;
        }
        else
        {
            printf("服务端返回消息:%s", buf);
        }
    }
    return 0;
}

套接字赋值

当我们对套接字进行赋值时,需要将IP地址以及端口号转换为网络字节序。port类型为 unsigned short;对于IP字符的转换有多个接口,可自行查阅。

read判定退出状态

无论当我们关闭哪一方套接字时,都会向另一方发送一个EOF(表明数据发送完毕),所以读取到的字符数为0。

总结

本节仅对socket最基本的轮子进行了使用的介绍,让入门的同学知道客户端与服务端的建立连接并进行通信的流程,下一节我们将深入了解这些轮子。