计算机网络自顶向下(3)---TCPsocket

news2024/10/17 19:25:49

1.TCPsocket

        TCPsocket是指使用传输控制协议(TCP)的网络套接字。套接字是网络中两台计算机之间进行通信的端点。TCP是一种可靠的、面向连接的协议,提供了错误检测、流量控制和拥塞控制等功能。

        TCPsocket通常用于客户端-服务器通信,其中客户端程序通过TCP/IP网络连接到服务器程序。客户端和服务器可以通过TCP套接字发送和接收TCP数据包来交换数据。

2.Linux中的TCPsocket

        在Linux中,TCPsocket是一种在网络编程中使用的套接字,用于建立TCP连接并进行数据交换。

在Linux中,使用C语言编写网络程序通常涉及到以下的系统调用和函数来创建和使用TCPsocket:

  1. socket()函数:用于创建一个新的套接字,返回一个套接字描述符(文件描述符)。

  2. bind()函数:将一个本地地址绑定到套接字。

  3. listen()函数:将套接字设置为监听状态,接受客户端的连接请求。

  4. accept()函数:接受客户端的连接请求,并返回一个新的套接字描述符,用于与客户端进行通信。

  5. connect()函数:用于与远程服务器建立TCP连接。

  6. send()和recv()函数:用于发送和接收数据。

  7. close()函数:关闭套接字连接。

        通过这些函数,可以在Linux中创建TCPsocket并进行数据通信。在编程中,可以使用套接字描述符进行读取和写入操作,来发送和接收数据。

当使用TCPsocket进行网络编程时,以下是对这些函数接口的详细介绍:

        socket()函数:创建一个新的套接字,返回一个套接字描述符(file descriptor)。函数原型为:

int socket(int domain, int type, int protocol);
  • domain参数指定套接字的地址族(address family),如AF_INET表示IPv4地址族、AF_INET6表示IPv6地址族。
  • type参数指定套接字的类型,如SOCK_STREAM表示TCP套接字、SOCK_DGRAM表示UDP套接字。
  • protocol参数指定套接字使用的协议,通常选择0,由操作系统根据套接字类型自动选择合适的协议。

        bind()函数:将一个本地地址绑定到套接字。函数原型为:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd参数为套接字描述符。
  • addr参数为要绑定的本地地址,通常使用结构体sockaddr_in(IPv4)或sockaddr_in6(IPv6)来表示。
  • addrlen参数为addr结构体的大小。

        listen()函数:将套接字设置为监听状态,接受客户端的连接请求。函数原型为:

int listen(int sockfd, int backlog);
  • sockfd参数为套接字描述符。
  • backlog参数指定等待连接队列的最大长度。

        accept()函数:接受客户端的连接请求,并返回一个新的套接字描述符,用于与客户端进行通信。函数原型为:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockfd参数为监听套接字描述符。
  • addr参数为指向用于存储客户端地址的结构体指针。
  • addrlen参数为指向addr结构体大小的指针。

        connect()函数:用于与远程服务器建立TCP连接。函数原型为:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd参数为套接字描述符。
  • addr参数为远程服务器的地址。
  • addrlen参数为addr结构体的大小。

        send()和recv()函数:用于发送和接收数据。函数原型分别为:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd参数为套接字描述符。
  • buf参数为数据的缓冲区。
  • len参数为数据的长度。
  • flags参数为可选的标志,如0表示无特殊选项。

        close()函数:关闭套接字连接。函数原型为:

int close(int sockfd);
  • sockfd参数为套接字描述符。
#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
    USAGE_ERROR
};

const static int defaultsockfd = -1;
const static int gbacklog = 16;

class TcpServer;

class ThreadData
{
public:
    ThreadData(int fd, InetAddr addr, TcpServer *s):sockfd(fd), clientaddr(addr), self(s)
    {}
public:
    int sockfd;
    InetAddr clientaddr;
    TcpServer *self;
};

using task_t = std::function<void()>;

class TcpServer
{
public:
    TcpServer(int port) : _port(port), _listensock(defaultsockfd), _isrunning(false)
    {
    }
    void InitServer()
    {
        // 1. 创建流式套接字
        _listensock = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LOG(FATAL, "socket error");
            exit(SOCKET_ERROR);
        }
        LOG(DEBUG, "socket create success, sockfd is : %d\n", _listensock);

        // 2. bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n = ::bind(_listensock, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "bind error");
            exit(BIND_ERROR);
        }
        LOG(DEBUG, "bind success, sockfd is : %d\n", _listensock);

        // 3. tcp是面向连接的,所以通信之前,必须先建立连接。服务器是被连接的
        //    tcpserver 启动,未来首先要一直等待客户的连接到来
        n = ::listen(_listensock, gbacklog);
        if (n < 0)
        {
            LOG(FATAL, "listen error");
            exit(LISTEN_ERROR);
        }
        LOG(DEBUG, "listen success, sockfd is : %d\n", _listensock);
    }
    void Service(int sockfd, InetAddr client)
    {
        LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.Ip().c_str(), client.Port(), sockfd);

        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]# ";
        while (true)
        {
            char inbuffer[1024];
            ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if (n > 0)
            {
                inbuffer[n] = 0;
                std::cout << clientaddr << inbuffer << std::endl;

                std::string echo_string = "[server echo]# ";
                echo_string += inbuffer;

                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0)
            {
                // client 退出&&关闭连接了
                LOG(INFO, "%s quit\n", clientaddr.c_str());
                break;
            }
            else
            {
                LOG(ERROR, "read error\n", clientaddr.c_str());
                break;
            }
	    sleep(5);
	    break;
        }
	std::cout << "server开始退出" << std::endl;
	shutdown(sockfd, SHUT_RD);
	std::cout << "shut _ rd " << std::endl;
	sleep(10);
	//shutdown(sockfd, SHUT_WR);
	//std::cout << "shut _ wr " << std::endl;
        //::close(sockfd); // 文件描述符泄漏
    }
    static void *HandlerSock(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->self->Service(td->sockfd, td->clientaddr);
        delete td;
        return nullptr;
    }
    void Loop()
    {
        _isrunning = true;
        // 4. 不能直接接受数据,先获取连接
        while (_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = ::accept(_listensock, (struct sockaddr *)&peer, &len);
            if (sockfd < 0)
            {
                LOG(WARNING, "accept error\n");
                continue;
            }
            // Version 0 : 一次只能处理一个请求 --- 不可能
            // Service(sockfd, InetAddr(peer));

            // Version 1: 采用多进程
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     // child : 关心sockfd, 不关心listensock
            //     ::close(_listensock); // 建议
            //     if(fork() > 0) exit(0); 
            //     Service(sockfd, InetAddr(peer)); //孙子进程 -- 孤儿进程 --- 系统领养
            //     exit(0);
            // }

            // // father: 关心listensock,不关心sockfd
            // ::close(sockfd);
            // waitpid(id, nullptr, 0);

            // version 2: 采用多线程
            pthread_t t;
            ThreadData *td = new ThreadData(sockfd, InetAddr(peer), this);
            pthread_create(&t, nullptr, HandlerSock, td); //将线程分离

            // vesion 3: 采用线程池
            // task_t t = std::bind(&TcpServer::Service, this, sockfd, InetAddr(peer));
            // ThreadPool<task_t>::GetInstance()->Enqueue(t);
        }
        _isrunning = false;
    }
    ~TcpServer()
    {
        if (_listensock > defaultsockfd)
            ::close(_listensock);
    }

private:
    uint16_t _port;
    int _listensock;
    bool _isrunning;
};
#include <iostream>
#include <string>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " serverip serverport\n"
              << std::endl;
}

// ./tcp_client serverip serverport
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "socket error" << std::endl;
        exit(2);
    }

    // tcp client 要bind,不要显示的bind.
    struct sockaddr_in server;
    // 构建目标主机的socket信息
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    int n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));
    if (n < 0)
    {
        std::cerr << "connect error" << std::endl;
        exit(3);
    }

    while(true)
    {
        std::cout << "Please Enter# ";
        std::string outstring;
        std::getline(std::cin, outstring);

        ssize_t s = send(sockfd, outstring.c_str(), outstring.size(), 0); //write
        if(s > 0)
        {
            char inbuffer[1024];
            ssize_t m = recv(sockfd, inbuffer, sizeof(inbuffer)-1, 0);
            if(m > 0)
            {
                inbuffer[m] = 0;
                std::cout << inbuffer<< std::endl;
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    //shutdown(sockfd, SHUT_WR);
    ::close(sockfd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2217256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软考(网工)——局域网和城域网

&#x1f550;局域网基础 1️⃣局域网和城域网体系架构 IEEE&#xff08;负责链路层&#xff09; 2️⃣局域网拓扑结构 局域网的主要特征由网络的拓扑结构、所采用的协议类型&#xff0c;以及介质访问控制方法决定。局域网的拓扑结构是指连接网络设备的传输介质的铺设形式&am…

爬虫逆向学习(十二):一个案例入门补环境

此分享只用于学习用途&#xff0c;不作商业用途&#xff0c;若有冒犯&#xff0c;请联系处理 反爬前置信息 站点&#xff1a;aHR0cDovLzEyMC4yMTEuMTExLjIwNjo4MDkwL3hqendkdC94anp3ZHQvcGFnZXMvaW5mby9wb2xpY3k 接口&#xff1a;/xjzwdt/rest/xmzInfoDeliveryRest/getInfoDe…

AI驱动的零售未来:打造无缝、智能、个性化的购物新世界

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 Shelly AI 工具集&#xff1a; 100个AI&am…

【私有云盘搭建】Portainer CE部署NextCloud,轻松实现公网访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【Linux系统查看磁盘占用情况】

文章目录 概要df 命令du 命令ls 命令 概要 在 Linux 系统中&#xff0c;查看磁盘占用情况可以使用以下几种常用的命令&#xff1a;df查看系统磁盘空间&#xff1b;du&#xff1a;查看目录的磁盘使用情况&#xff1b;ls&#xff1a;列出目录内容的基本命令 df 命令 可以显示文…

JAVA就业笔记7——第二阶段(4)

课程须知 A类知识&#xff1a;工作和面试常用&#xff0c;代码必须要手敲&#xff0c;需要掌握。 B类知识&#xff1a;面试会问道&#xff0c;工作不常用&#xff0c;代码不需要手敲&#xff0c;理解能正确表达即可。 C类知识&#xff1a;工作和面试不常用&#xff0c;代码不…

Gin框架操作指南08:日志与安全

官方文档地址&#xff08;中文&#xff09;&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;本教程采用工作区机制&#xff0c;所以一个项目下载了Gin框架&#xff0c;其余项目就无需重复下载&#xff0c;想了解的读者可阅读第一节&#xff1a;Gin操作指南&#…

【C++】红黑树模拟实现map和set

本篇基于上篇红黑树的代码来实现&#xff1a; 【C】红黑树-CSDN博客 关于map和set可以看&#xff1a;​​​​ 【C】map和set的介绍和使用-CSDN博客 改造红黑树 map底层是红黑树的KV模型&#xff0c;set是红黑树的K模型&#xff0c;按理来说&#xff0c;应该设计两种红黑树来…

企业培训平台开发指南:基于在线教育系统源码的实现路径解析

本篇文章&#xff0c;小编将通过对在线教育系统源码的解读&#xff0c;深入探讨企业培训平台的开发路径&#xff0c;帮助企业高效构建适合自身需求的培训系统。 一、企业培训平台的需求分析 在开发企业培训平台之前&#xff0c;首先要对企业的实际需求进行充分分析。每个企业…

各种开发编程软件的下载方法--visio,navicat,pycharm,matlab等

各类开发编程类软件的下载方法 一、需要付费的 之前在网络上有很多显示可以免费下载的软件&#xff0c;不是各种在解压时需要密码的&#xff0c;就是有各种病毒的&#xff0c;绕一圈可能还得收费。 最早之前用的是 “A软件安装管家” 这个公众号里的&#xff0c;后来停更了&…

【优选算法篇】双指针的华丽探戈:深入C++算法殿堂的优雅追寻

文章目录 C 双指针详解&#xff1a;进阶题解与思维分析前言第一章&#xff1a;有效三角形的个数1.1 有效三角形的个数示例 1&#xff1a;示例 2&#xff1a;解法一&#xff08;暴力求解&#xff09;解法二&#xff08;排序 双指针&#xff09;易错点提示代码解读 第二章&#…

C++的魔法世界:类和对象的终章

文章目录 一、再探构造函数二、类型转换2.1隐式类型转换2.2内置类型的类型转化2.3explicit关键字2.4多参数构造 三、static成员四、友元五、内部类内部类的特性 六、匿名对象 一、再探构造函数 类和对象(中)里介绍的构造函数&#xff0c;使用的是赋值实现成员变量的初始化。而…

【word】文章里的表格边框是双杠

日常小伙伴们遇到word里插入的表格&#xff0c;边框是双杠的&#xff0c;直接在边框和底纹里修改边框的样式就可以&#xff0c;但我今天遇到的这个有点特殊&#xff0c;先看看表格在word里的样式是怎么样&#xff0c;然后我们聊聊如何解决。 这个双杠不是边框和底纹的设置原因…

亚洲 Web3 市场:Q3 监管变化与市场驱动力探析

概述&#xff1a; 亚洲的 Web3 市场在2024年第三季度继续表现出强劲增长势头。得益于技术精通的人口基础、政府的积极政策导向和企业的大规模参与&#xff0c;韩国、日本、越南等国家已然走在行业前沿。此外&#xff0c;随着越来越多的监管框架落地&#xff0c;区块链创新不断…

Ubuntu20.04下安装多CUDA版本,以及后续切换卸载

本方案的前提是假设机子上已经有一个版本的cuda&#xff0c;现在需要支持新的torch2.1.2和torchvision0.16.2&#xff0c;于是来安装新的cuda 一、选择版本 如果我想安装支持torch2.1.2的cuda版本&#xff0c;到官网&#xff08;https://pytorch.org/get-started/previous-ve…

【Python文件操作】掌握文件读写和目录管理的技巧!

【Python文件操作】掌握文件读写和目录管理的技巧&#xff01; 在现代编程中&#xff0c;文件操作是不可避免的一部分&#xff0c;尤其是在处理数据、日志、配置文件等场景下。Python 提供了强大而简洁的文件操作方法&#xff0c;可以轻松完成文件的读取、写入和目录管理等操作…

005_django基于Python的乡村居民信息管理系统设计与实现2024_106f2qg9

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

SpringMVC源码-异常处理机制

定义一个异常处理类TestErrorController: Controller public class TestErrorController {RequestMapping("/exception")public ModelAndView exception(ModelAndView view) throws ClassNotFoundException {view.setViewName("index");throw new ClassNot…

Mysql主从集群搭建+分库分表+ShardingSphere(实战)

什么是 ShardingSphere 介绍 Apache ShardingSphere 是一款分布式的数据库生态系统&#xff0c; 可以将任意数据库转换为分布式数据库&#xff0c;并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 Apache ShardingSphere 设计哲学为 Database Plus&#xff0c;…

CRMEB标准版Mysql修改sql_mode

数据库配置 1.宝塔控制面板-软件商店-MySql-设置 2.点击配置修改&#xff0c;查找sql-mode或sql_mode &#xff08;可使用CtrlF快捷查找&#xff09; 3.复制 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 然后替换粘贴&#xff0c;保存 注&#xff1a;MySQL8.0版本的 第三步用…