首页 > 其他分享 >【技术学习】网络学习--简单tcp服务器

【技术学习】网络学习--简单tcp服务器

时间:2023-06-17 20:11:06浏览次数:29  
标签:-- tcp 学习 buffer client 服务器 include 连接 客户端

这是一个用AI生成的简单的tcp服务器代码,我稍微改动了一下命名啥的。

可以看到代码非常简短,不过却没什么问题,人工智能还是很强的。

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstring>
#include <unistd.h>

#define MAXLNE  4096

int main() {
    int listenfd, connfd;
    struct sockaddr_in servaddr{};
    char buffer[MAXLNE]{};

    // 创建套接字
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1) {
        std::cerr << "Failed to create socket." << std::endl;
        return -1;
    }

    // 设置服务器地址
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(8080); // 指定端口号(这里使用8080)
    servaddr.sin_addr.s_addr = INADDR_ANY;

    // 绑定套接字到指定地址和端口
    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        std::cerr << "Failed to bind socket." << std::endl;
        return -1;
    }

    // 监听连接请求
    if (listen(listenfd, 5) < 0) { // 允许同时处理最多5个连接请求
        std::cerr << "Error in listening." << std::endl;
        return -1;
    }

    std::cout << "Server started. Listening for incoming connections..." << std::endl;

    while (true) {
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        // 接受连接请求
        connfd = accept(listenfd, (struct sockaddr *)&client, &len);
        if (connfd < 0) {
            std::cerr << "Error in accepting connection." << std::endl;
            return -1;
        }
        
        // 读取客户端发来的数据
        bzero(buffer, sizeof(buffer));
        if (read(connfd, buffer, sizeof(buffer)) < 0) {
            std::cerr << "Error in reading data." << std::endl;
            return -1;
        }

        // 输出客户端发送的消息
        std::cout << "Client message: " << buffer << std::endl;

        // 发送响应给客户端
        const char *response = "Hello from server!";
        if (write(connfd, response, strlen(response)) < 0) {
            std::cerr << "Error in sending response." << std::endl;
            return -1;
        }

        // 关闭连接套接字
        close(connfd);
    }

    // 关闭服务器套接字
    close(listenfd);

    return 0;
}

如果我们运行这个代码,会发现它只能和client完成单次的连接和发送消息,消息发送完就会断开连接并等待client再次连接。同时,这个服务器采用的是一种基于阻塞式I/O的方式,如果有一个客户端连接上并没有关闭连接,后续连接上服务器的客户端会被阻塞在accept上,无法获得服务器的响应,直到前面的客户端关闭连接。

如果我想得到一个可以多客户端同时连接,且可以保持连接循环发消息的服务器代码的话,就可以使用多线程方式。

首先在main前写一个多线程处理客户端的函数handle_client:

void *handle_client(void *arg) 
{ int connfd = *(int *)arg; char buffer[MAXLNE]{}; while(1) { // 读取客户端发来的数据 bzero(buffer, sizeof(buffer)); if (read(connfd, buffer, sizeof(buffer)) < 0) { std::cerr << "Error in reading data." << std::endl; close(connfd); return NULL; } // 输出客户端发送的消息 std::cout << "Client message: " << buffer << std::endl; // 发送响应给客户端 const char *response = "Hello from server!"; if (write(connfd, response, strlen(response)) < 0) { std::cerr << "Error in sending response." << std::endl; } } }

然后改一下while循环多线程调起

while (1) 
{ struct sockaddr_in client; socklen_t len = sizeof(client); // 接受连接请求 connfd = accept(listenfd, (struct sockaddr *)&client, &len); if (connfd < 0) { std::cerr << "Error in accepting connection." << std::endl; return -1; } // 创建一个新的线程处理客户端连接 pthread_t threadid; pthread_create(&threadid, NULL, handle_client, (void*)&connfd); }

连接效果如图

 可以看到,多个客户端同时连接访问,并发送接收消息都是没问题的。

该方式可以应对小量连接请求,客户端退出线程退出,在预估客户端同时使用不多的情况下是可用的。但毕竟多线程内存开销还是比较大的,在面对庞大的客户端访问时是非常不友好的。

标签:--,tcp,学习,buffer,client,服务器,include,连接,客户端
From: https://www.cnblogs.com/templeD/p/17488144.html

相关文章

  • 正则表达式匹配:元字符、分组匹配、数量匹配
    数量匹配: ......
  • 派大星
     #include<iostream>#include"minecraft.h"#include<Windows.h>usingnamespacestd;TxMinecraftmc;intmain(){boolcon=mc.ConnectMinecraft("zk","08bd17c1ea594f2684182fd956c2d172");if(!con){......
  • 数据验证序列自动去重(Excel技巧集团)
    数据验证》序列》来源,输入一行或一列数据,就可以从下拉选项中选取需要输入的数据。当数据源是一列带有重复值的数据时,下拉选项里也会忠实地显示所有内容,包括重复的内容。如果想要去重,就必须添加辅助列。但那都是过去子,现在,就只要直接…… ......
  • Cypress自动化测试
    基础知识Sypress是一个E2E测试框架使用的是流行的测试框架mocha(浏览器的操作)andchai(断言)不同于selenium,没有webdrive,而是直接通过devdrive调用浏览器,执行效率更高  功能时间旅行(TimeTravel) 可以重现运行场景,不用一直等在屏幕前进行操作,每一步都有截图sel......
  • cn小系统
    一级导航二级导航列表storeId/categories/list(门店-分类-列表)store#1id=1storeId、categoriesId、fieldExt(month、type)(返回这几个字段、点击列表都要传2个字段给接口)id=2id=3store#2store#3store#4store#5type:check、cash、billcategories:列表id对应固定分类id=1:p......
  • 派大星
    #include<iostream>#include<string>#include"minecraft.h"#include<Windows.h>usingnamespacestd;TxMinecraftmc;intmain(intargc,char**argv){boolcon=mc.ConnectMinecraft("zk.makeblock.net.cn","868......
  • 批量插入图片(Excel技巧集团)
    以前插入图片以后,图片是在单元格上方的,且同时插入多张图片后,那效果……不忍目睹。但是现在,多出来了个【旋转在单元格中】的功能,图片变成了单元格对象。不止如此,这些图片还可以成为数据验证序列的来源。MM再也不用担心我不会做带照片的花名册了哈哈哈……......
  • Springboot整合mongodb
    入门案例创建工程,导入依赖导入依赖点击查看代码<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId><version>2.3.9.RELEASE</version>......
  • 删除最前面的横杠(Power Query)
    问题:一列数据存在若干横杠,只需要删除第一个文字前的横杠。let源=Excel.CurrentWorkbook(){[Name="表2"]}[Content],每个单元格一个字符=Table.SplitColumn(源,"列1",Splitter.SplitTextByRepeatedLengths(1),{"列1.1","列1.2","列1.3","列......
  • 派大星
    #include<iostream>#include<string>#include"minecraft.h"#include"Windows.h"TxMinecraftmc;usingnamespacestd;stringid,data;intx,y,z;intmain(){boolcon=mc.ConnectMinecraft("zk","919b005179e840......