linux服务器的创建模板及原理

基础版

一次信息传递后双端退出

服务器端:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <netinet/in.h>  
#include <sys/socket.h>  
  
#define PORT 8080  
#define BUF_SIZE 1024  
  
int main() {  
    int server_fd, new_socket;  
    struct sockaddr_in address;  
    int opt = 1;  
    int addrlen = sizeof(address);  
    char buffer[BUF_SIZE] = {0};  
    char *hello = "Hello from server";  
  
    // 创建socket文件描述符  
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {  
        perror("socket failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 绑定socket到端口8080  
    address.sin_family = AF_INET;  
    address.sin_addr.s_addr = INADDR_ANY;  
    address.sin_port = htons(PORT);  
  
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {  
        perror("bind failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 监听端口  
    if (listen(server_fd, 3) < 0) {  
        perror("listen");  
        exit(EXIT_FAILURE);  
    }  
  
    // 等待客户端连接  
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {  
        perror("accept");  
        exit(EXIT_FAILURE);  
    }  
  
    // 读取客户端发送的数据  
    read(new_socket, buffer, BUF_SIZE);  
    printf("%s\n", buffer);  
  
    // 发送数据到客户端  
    send(new_socket, hello, strlen(hello), 0);  
    printf("Hello message sent\n");  
  
    // 关闭socket  
    close(server_fd);  
    close(new_socket);  
  
    return 0;  
}
1. socket() 函数

功能:创建一个新的套接字。

原型int socket(int domain, int type, int protocol);

参数

  • domain:指定协议族。对于IPv4,通常是AF_INET;对于IPv6,是AF_INET6
  • type:指定套接字类型。对于TCP连接,使用SOCK_STREAM;对于UDP连接,使用SOCK_DGRAM
  • protocol:指定具体的协议。通常设置为0,让系统自动选择适合domaintype的协议。

返回值:成功时返回一个新的套接字文件描述符,失败时返回-1并设置errno。

2. bind() 函数

功能:将套接字绑定到一个特定的IP地址和端口号上。

原型int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数

  • sockfd:要绑定的套接字文件描述符。
  • addr:指向sockaddr结构的指针,该结构包含IP地址和端口号。对于IPv4,通常使用sockaddr_in结构。
  • addrlenaddr参数指向的结构的长度。

返回值:成功时返回0,失败时返回-1并设置errno。

3. listen() 函数

功能:使套接字进入监听状态,准备接受客户端的连接请求。

原型int listen(int sockfd, int backlog);

参数

  • sockfd:要监听的套接字文件描述符。
  • backlog:指定系统应该为等待处理的连接请求所排队的最大数量。

返回值:成功时返回0,失败时返回-1并设置errno。

4. accept() 函数

功能:接受一个连接请求,如果连接被接受,则创建一个新的套接字用于与客户端通信。

原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数

  • sockfd:处于监听状态的套接字文件描述符。
  • addr:一个输出参数,用于存储客户端的地址信息。如果不需要,可以设置为NULL。
  • addrlen:一个输入/输出参数,指定addr的大小,并在成功时更新为实际返回的地址长度。

返回值:成功时返回一个新的套接字文件描述符,用于与客户端通信;失败时返回-1并设置errno。

5. send() 和 recv() 函数(或在UNIX/Linux中使用send()/sendto()recv()/recvfrom()

功能

  • send():通过套接字发送数据。
  • recv():从套接字接收数据。

注意:在UNIX/Linux中,send()recv()是更通用的函数,用于TCP连接。对于UDP,通常使用sendto()recvfrom(),因为它们允许指定数据的目的地址和来源地址。

原型(以send()为例):ssize_t send(int sockfd, const void *buf, size_t len, int flags);

参数

  • sockfd:套接字文件描述符。
  • buf:指向要发送数据的缓冲区的指针。
  • len:要发送数据的长度。
  • flags:通常设置为0。

返回值:成功时返回发送的字节数,失败时返回-1并设置errno。

客户端:

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <string.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
  
#define PORT 8080  
  
int main() {  
    struct sockaddr_in serv_addr;  
    int sock = 0;  
    char *hello = "Hello from client";  
    char buffer[1024] = {0};  
  
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  
        printf("\n Socket creation error \n");  
        return -1;  
    }  
  
    serv_addr.sin_family = AF_INET;  
    serv_addr.sin_port = htons(PORT);  
  
    // 将IPv4地址从文本转换成二进制形式  
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {  
        printf("\nInvalid address/ Address not supported \n");  
        return -1;  
    }  
  
    // 连接到服务器  
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {  
        printf("\nConnection Failed \n");  
        return -1;  
    }  
  
    // 发送数据到服务器  
    send(sock, hello, strlen(hello), 0);  
    printf("Hello message sent\n");  
  
    // 接收服务器回显的数据  
    int valread = read(sock, buffer, 1024);  
    printf("%s\n", buffer);  
  
    // 关闭socket  
    close(sock);  
  
    return 0;  
}

进阶版

重复进行数据交换,直到客户端输入exit

服务器端

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

#define PORT 8080  
#define BUF_SIZE 1024  

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUF_SIZE] = {0};
    char *hello = "Hello from server";

    // 创建socket文件描述符  
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 绑定socket到端口8080  
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听端口  
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 等待客户端连接  
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
        perror("accept");
                               exit(EXIT_FAILURE);
    }
while (1) {
        // 读取客户端发送的数据  
        int bytes_read = read(new_socket, buffer, BUF_SIZE - 1); // 保留一个字节给 '\0'  
        if (bytes_read < 0) {
            perror("read failed");
            break; // 或者可以关闭 socket 并退出循环  
        }
        buffer[bytes_read] = '\0'; // 确保字符串以 '\0' 结尾  

        // 检查是否接收到 "exit"  
        if (strcmp(buffer, "exit") == 0) {
            break; // 退出循环  
        }

        printf("%s\n", buffer);

        // 发送数据到客户端  
        send(new_socket, hello, strlen(hello), 0);
        printf("Message sent: %s\n", hello);
    }
    // 关闭socket  
    close(server_fd);
    close(new_socket);

    return 0;
}
       

客户端

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

#define PORT 8080  
#define BUFFER_SIZE 1024
int main() {
    struct sockaddr_in serv_addr;
    int sock = 0;

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 将IPv4地址从文本转换成二进制形式  
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    // 连接到服务器  
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }

    char buffer[BUFFER_SIZE] = {0}; // 用于接收服务器响应的缓冲区  
    char input_buffer[BUFFER_SIZE] = {0}; // 用于存储用户输入的缓冲区  

     while (1) {
        printf("Type in the message you want to send (or 'exit' to quit): ");
        if (fgets(input_buffer, sizeof(input_buffer), stdin) == NULL) {
            perror("fgets failed");
            break;
        }

        // 去除 fgets 读取的换行符(如果有)  
        input_buffer[strcspn(input_buffer, "\n")] = 0;

        if (strcmp(input_buffer, "exit") == 0) {
            break;
        }

        // 发送数据到服务器  
        send(sock, input_buffer, strlen(input_buffer), 0);
        printf("Message sent\n");

        // 接收服务器回显的数据  
        int valread = read(sock, buffer, BUFFER_SIZE - 1);
        if (valread < 0) {
            perror("read failed");
            break;
        }
        buffer[valread] = '\0'; // 确保字符串以空字符结尾  
        printf("%s\n", buffer);
    }
    // 关闭socket  
    close(sock);

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值