首页 > 系统相关 >Linux TCP/UDP CS模型

Linux TCP/UDP CS模型

时间:2024-03-19 18:55:24浏览次数:31  
标签:serv UDP addr TCP SERVER CS 服务器 include

Linux TCP/UDP CS模型

目录

TCP Server/TCP Client

在C语言中实现一个TCP服务器时,使用select函数可以帮助我们同时监控多个文件描述符(包括socket)的状态,从而实现非阻塞的I/O操作。以下是一个简单的TCP服务器示例,它使用select来同时监听多个客户端连接,并处理它们发送的数据。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>  
#include <arpa/inet.h>  
#include <sys/time.h>  
#include <errno.h>  
#include <sys/types.h>  
  
#define SERVER_PORT 8080  
#define MAX_CLIENTS 10  
#define MAX_TIMEOUT 10  
#define BUFFER_SIZE 1024  
  
#define print(fmt, args...) printf("\033[1m[ %s ] %03d: "fmt"\033[0m\n\r", __FUNCTION__, __LINE__, ##args)
int main() {  
    int server_fd, new_socket, max_sd;
    struct sockaddr_in address;
    int addrlen, opt = 1;
    fd_set readfds;
    struct timeval tv;
    char buffer[BUFFER_SIZE] = {0};
    int i, valread;
  
    // 创建socket文件描述符 
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {  
        perror("socket failed");
        exit(EXIT_FAILURE);
    }  
  
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {  
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }  
  
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(SERVER_PORT);
  
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {  
        perror("bind failed");
        exit(EXIT_FAILURE);
    }  
  
    if (listen(server_fd, MAX_CLIENTS) < 0) {  
        perror("listen");
        exit(EXIT_FAILURE);
    }  
  
    max_sd = server_fd;
  
    while (1) {  
        FD_ZERO(&readfds);
        FD_SET(server_fd, &readfds);
  
        tv.tv_sec = MAX_TIMEOUT;
        tv.tv_usec = 0;
  
        int activity = select(max_sd + 1, &readfds, NULL, NULL, &tv);
  
        if ((activity < 0) && (errno != EINTR)) {  
            perror("select");
            continue;
        }  

        if (!FD_ISSET(server_fd, &readfds)) {
            continue;
        }
  
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {  
            perror("accept");
            continue;
        }

        if ((valread = read(new_socket, buffer, BUFFER_SIZE)) > 0) {  
            buffer[valread] = '\0';
            printf("Received from client %d: %s\n", new_socket, buffer);
            send(new_socket, "Hello from server", strlen("Hello from server"), 0);
        }

        close(new_socket);
    }

    close(server_fd);
    return 0;
}

在C语言中,创建一个TCP客户端主要涉及以下几个步骤:

  1. 创建套接字(socket)。
  2. 设置服务器的地址信息。
  3. 连接到服务器(connect)。
  4. 发送和接收数据。
  5. 关闭套接字。

以下是一个简单的TCP客户端的C语言实现:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
  
#define SERVER_IP "127.0.0.1"  
#define SERVER_PORT 8080  
#define BUFFER_SIZE 1024  
  
int main() {  
    int sock;  
    struct sockaddr_in serv_addr;  
    char buffer[BUFFER_SIZE] = {0};  
    char *message = "Hello from client";  
    ssize_t bytes_sent, bytes_received;  
  
    // 创建socket文件描述符  
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  
        perror("socket creation failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 设置服务器的地址信息  
    memset(&serv_addr, '0', sizeof(serv_addr));  
    serv_addr.sin_family = AF_INET;  
    serv_addr.sin_port = htons(SERVER_PORT);  
  
    // 将IPv4地址从点分十进制转换为二进制形式  
    if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {  
        perror("invalid address/address not supported");  
        exit(EXIT_FAILURE);  
    }  
  
    // 连接到服务器  
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {  
        perror("connection failed");  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Connected to server.\n");  
  
    // 发送消息到服务器  
    bytes_sent = send(sock, message, strlen(message), 0);  
    if (bytes_sent < 0) {  
        perror("send failed");  
        exit(EXIT_FAILURE);  
    } else {  
        printf("Sent %zd bytes: %s\n", bytes_sent, message);  
    }  
  
    // 从服务器接收响应  
    bytes_received = recv(sock, buffer, BUFFER_SIZE - 1, 0);  
    if (bytes_received < 0) {  
        perror("recv failed");  
        exit(EXIT_FAILURE);  
    } else if (bytes_received == 0) {  
        printf("Server closed the connection.\n");  
    } else {  
        buffer[bytes_received] = '\0';  
        printf("Received %zd bytes: %s\n", bytes_received, buffer);  
    }  
  
    // 关闭套接字  
    close(sock);  
    return 0;  
}

这个程序会尝试连接到位于SERVER_IPSERVER_PORT的服务器,并发送一个简单的消息Hello from client。之后,它会尝试从服务器接收数据,并将其打印到控制台上。如果在sendrecv函数中发生错误,程序会打印出错误信息并退出。

请注意,这个客户端程序假设服务器在发送完数据后会关闭连接,或者发送的数据量不会超过BUFFER_SIZE - 1。在实际应用中,你可能需要处理更复杂的情况,比如服务器持续发送数据,或者数据可能分多个包到达。

编译和运行这个客户端程序,你需要一个TCP服务器正在监听SERVER_IPSERVER_PORT。如果服务器没有运行,connect调用将失败。

编译命令可能类似于:

gcc client.c -o client

然后运行编译好的程序:

./client

确保你的TCP服务器已经启动并监听在指定的IP地址和端口上。

UDP Server/UDP Client

在C语言中实现一个UDP服务器,你需要执行以下步骤:

  1. 创建一个UDP套接字(socket)。
  2. 绑定套接字到一个本地地址和端口。
  3. 接收客户端发送的数据(recvfrom)。
  4. 发送响应数据给客户端(sendto)。
  5. 关闭套接字。

以下是一个简单的UDP服务器示例:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
  
#define SERVER_PORT 8080  
#define BUFFER_SIZE 1024  
  
int main() {  
    int sock;  
    struct sockaddr_in serv_addr, cli_addr;  
    socklen_t cli_len;  
    char buffer[BUFFER_SIZE] = {0};  
    ssize_t bytes_received;  
  
    // 创建UDP套接字  
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {  
        perror("socket creation failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 设置服务器地址信息  
    memset(&serv_addr, 0, sizeof(serv_addr));  
    serv_addr.sin_family = AF_INET;  
    serv_addr.sin_addr.s_addr = INADDR_ANY;  
    serv_addr.sin_port = htons(SERVER_PORT);  
  
    // 绑定套接字到地址和端口  
    if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {  
        perror("bind failed");  
        exit(EXIT_FAILURE);  
    }  
  
    printf("Server started on port %d\n", SERVER_PORT);  
  
    cli_len = sizeof(cli_addr);  
  
    // 循环接收客户端数据  
    while (1) {  
        // 接收数据  
        bytes_received = recvfrom(sock, buffer, BUFFER_SIZE - 1, 0,  
                                   (struct sockaddr*)&cli_addr, &cli_len);  
        if (bytes_received < 0) {  
            perror("recvfrom failed");  
            break;  
        }  
  
        buffer[bytes_received] = '\0'; // 确保字符串正确结束  
  
        printf("Received from %s:%d: %s\n",  
               inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buffer);  
  
        // 发送响应  
        sendto(sock, "Message received", strlen("Message received"), 0,  
               (struct sockaddr*)&cli_addr, cli_len);  
    }  
  
    // 关闭套接字  
    close(sock);  
    return 0;  
}

这段代码创建了一个UDP服务器,它监听在SERVER_PORT定义的端口上。当接收到客户端发送的数据时,服务器会打印出数据并发送一个确认消息回客户端。

要编译和运行这个服务器,你可以使用类似下面的命令:

gcc udp_server.c -o udp_server  
./udp_server

请确保没有其他的程序在SERVER_PORT定义的端口上监听,否则bind调用会失败。

为了测试这个服务器,你可以编写一个UDP客户端或者使用现有的网络工具(如ncnetcat)来发送UDP数据包到服务器的地址和端口。

例如,使用netcat作为客户端发送消息给服务器:

echo "Hello from client" | nc -u -w1 localhost 8080

这里的-u标志告诉netcat使用UDP协议,-w1设置等待响应的超时时间为1秒,localhost是服务器的地址,8080是服务器的端口。服务器应该接收并打印出消息,然后发送回一个响应。由于UDP是无连接的,客户端可能无法接收到服务器的响应,这取决于网络条件和客户端的实现。

在C语言中实现一个UDP客户端相对简单,主要步骤包括创建UDP套接字、向服务器发送数据以及接收服务器的响应。以下是一个简单的UDP客户端示例:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
  
#define SERVER_IP "127.0.0.1"  
#define SERVER_PORT 8080  
#define BUFFER_SIZE 1024  
  
int main() {  
    int sock;  
    struct sockaddr_in serv_addr;  
    char *message = "Hello from UDP client";  
    char buffer[BUFFER_SIZE] = {0};  
    ssize_t bytes_sent, bytes_received;  
  
    // 创建UDP套接字  
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {  
        perror("socket creation failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 设置服务器地址信息  
    memset(&serv_addr, 0, sizeof(serv_addr));  
    serv_addr.sin_family = AF_INET;  
    serv_addr.sin_port = htons(SERVER_PORT);  
    if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {  
        perror("invalid address/address not supported");  
        exit(EXIT_FAILURE);  
    }  
  
    // 发送数据到服务器  
    bytes_sent = sendto(sock, message, strlen(message), 0,  
                        (struct sockaddr*)&serv_addr, sizeof(serv_addr));  
    if (bytes_sent < 0) {  
        perror("sendto failed");  
        exit(EXIT_FAILURE);  
    } else {  
        printf("Sent %zd bytes: %s\n", bytes_sent, message);  
    }  
  
    // 接收服务器的响应  
    bytes_received = recvfrom(sock, buffer, BUFFER_SIZE - 1, 0,  
                               NULL, 0);  
    if (bytes_received < 0) {  
        perror("recvfrom failed");  
    } else if (bytes_received == 0) {  
        printf("Server closed the connection.\n");  
    } else {  
        buffer[bytes_received] = '\0'; // 确保字符串正确结束  
        printf("Received %zd bytes: %s\n", bytes_received, buffer);  
    }  
  
    // 关闭套接字  
    close(sock);  
    return 0;  
}

这段代码实现了一个简单的UDP客户端,它向位于SERVER_IPSERVER_PORT的服务器发送一条消息,并等待服务器的响应。

要编译和运行这个客户端,你可以使用以下命令:

gcc udp_client.c -o udp_client  
./udp_client

请确保你的UDP服务器已经启动并监听在指定的IP地址和端口上。客户端会发送消息到服务器,并尝试接收服务器的响应。如果服务器没有发送响应,客户端的recvfrom调用可能会阻塞,直到收到数据或发生错误。如果你希望客户端是非阻塞的,你需要在创建套接字后设置相应的套接字选项。

注意:UDP是无连接的协议,因此客户端发送消息后不一定能接收到服务器的响应,这取决于网络条件、服务器实现以及服务器的配置。如果服务器没有响应,客户端可能会无限期地等待。在实际应用中,你可能需要设置超时或重试机制来处理这种情况。

标签:serv,UDP,addr,TCP,SERVER,CS,服务器,include
From: https://www.cnblogs.com/adam-ma/p/18083701

相关文章

  • CSC209 系统故障 管道
    CSCSHELL截止时间为周日晚上11:59。积分2002月14日后12点开始发售。A3–CSCSHELLCSC2092024年冬季上次更新(3月15日):见5.7目录1.简介2.入门文件2.1.实际开始3.CSCSHELL4.限制(shell的东西你不必实现)5.实施和要求5.1.管理错误5.2.外壳变量5.2.1.创造5.2.2.用法5.2.3.路径5.2.4.......
  • 镭速,企业传输大文件都在用的udp文件传输工具
    在当今快速变化的数字世界中,文件传输工具已成为企业运营不可或缺的一部分。尤其是面对大文件传输的需求,传统的TCP协议由于其设计上的局限性,往往无法满足企业对高速、稳定传输的需求。这时,UDP文件传输工具以其独特的优势走进了人们的视野。UDP文件传输工具的优势与缺点UDP是......
  • 前端基础之CSS基础
    一、什么是cssCSS(CascadingStyleSheets的缩写),翻译为“层叠样式表”或者“级联样式表”,简称样式表。主要用来给HTML网页设置外观或者样式(HTML网页中的文字大小、颜色、字体、网页的背景颜色、背景图片等)。通俗来说就是给HTML标签添加样式的,让它变得更加好看二、注释语法......
  • 前端基础之CSS选择器
    一、什么是选择器选择器是指通过一定的语法规则选取到对应的HTML标记,然后给这个对应的HTML标记设置样式二、选择器的分类CSS中提供了多种不同类型的选择器,例如基本选择器、组合选择器、伪类选择器、伪元素选择器等等。1、基本选择器(1)概览在CSS中,选择器用于选取HTML文档中的......
  • CSS
    简介CSS(CascadingStyleSheets)层叠样式表,又叫级联样式表,简称样式表CSS文件后缀名为.cssCSS用于HTML文档中元素样式的定义目的使用css的唯一目的就是让网页具有美观一致的页面语法CSS规则由两个主要的部分构成:选择器,以及一条或多条声明(样式)选择器通常是您需要改变样式的......
  • 有趣的css - 音频小动效
    大家好,我是Just,这里是「设计师工作日常」,今天分享的是用css3实现一个好玩的音频小动效。《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。目录整体效果核心代码html代码css部分代码完整代码如下html页面css样式页面渲染效果整体效果使用......
  • Java-Java基础学习(2)-网络编程-TCP-UDP
    2.网络编程2.1.通信协议TCP、UDP对比TCP打电话连接,稳定三次握手,四次挥手三次握手A:你瞅啥?B:瞅你咋地?A:干一场!四次挥手A:我要走了B:你真的要走了吗?B:你真的真的要走了吗?A:我真的要走了客户端、服务端传输完成,释放连接,效率低UDP发短信不连......
  • Spring Data Elasticsearch 自定义检索字段比重,计算得分
    BoolQueryBuilderfuzzyQuery=QueryBuilders.boolQuery();String[]matchFieldNames={"itemName","categoryNames","baseCategoryName","materialNameAilas","materialName",......
  • ElasticSearch - 基础概念和映射
    前言写这篇东西,是因为官方文档看着太痛苦,于是乎想用大白话来聊聊ElasticSearc(下面都简称ES)。所以下文对于ES一些概念的表述可能会与官方有出入,所以需要准确的表述和详细定义的,请跳转官方文档。我也尽量贴上官方的链接。前置知识:因为下文会使用mysql的一些概念来描述,所以......
  • 基于多种优化算法的物联网无人机基站研究【布谷鸟搜索CS、大象群体优化EHO、灰狼优化G
     ......