计算机网络(3) --- 网络套接字TCP

这篇具有很好参考价值的文章主要介绍了计算机网络(3) --- 网络套接字TCP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

计算机网络(2) --- 网络套接字UDP_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131977544?spm=1001.2014.3001.5501

目录

1.TCP

1.服务端接口介绍

1.listen状态

2.accept获取链接

2.客户端接口介绍

2.TCP的服务器和客户端接口实现

1.服务端

1.成员函数

2.接口

start()实现方式

1.单一执行流

2.多进程

3.多线程

4.线程池

3.main函数

2.客户端

1.成员函数

2.接口

3.mian函数

3.守护进程化

1.守护进程

2.代码


1.TCP

回顾一下UDP套接字,实现很简单,只需要初始化然后再send即可。但是TCP更加复杂

1.服务端接口介绍

1.listen状态

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

listen状态适用于获取先链接的,第二个参数不能填太大的int类型数据。

2.accept获取链接

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

 服务器只有先accept获取新链接(客户端传来的套接字),才能接受到套接字。

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

1.调用成功返回一个文件描述符, 失败返回-1。这个返回值其实对应的是一个套接字。

2.第一个sockfd其实是接收用的套接字,它不参与到具体的操作内;而返回值返回的套接字才是客户端返回的套接字,这个套接字是用于处理的。

3.由于tcp是面向字节流的,所以接受到的套接字就可以使用read和write进行操作了

4.如果该套接字使用完毕,一定要释放(close)套接字。因为文件描述符的本质是数组,而数组有一定的上限,我们不能只入而不释放,如果不释放会出现文件描述符泄漏。

2.客户端接口介绍

1.connect:发起链接

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

链接对应服务端的ip和port,表示自己要链接哪个服务端

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

2.TCP的服务器和客户端接口实现

1.服务端

namespace Server
{
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
        OPEN_ERR
    };

    static const uint16_t gport = 8080;
    static const int gbacklog = 5;

    class tcpServer
    {
    public:
        tcpServer(const uint16_t &port = gport)
            : _listensock(-1), _port(port)
        {
        }

        void initServer()
        {
            // 1.创建
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensock < 0)
            {
                logMessage(FATAL, "create listensock error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create listensock success");

            // 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;
            if (bind(_listensock, (struct sockaddr *)&local, sizeof local) < 0)
            {
                logMessage(FATAL, "bind error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "bind listensock success");

            // 3.设置socket,为监听状态
            if (listen(_listensock, gbacklog))
            {
                logMessage(FATAL, "listen error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "listen listensock success");
        }

        void start()
        {
            for (;;)
            {
                // 单线程版,只能有一个执行流,其他的无法进入执行,因为serviceIO死循环
                // 1.sever获取新链接
                struct sockaddr_in peer;
                socklen_t len = sizeof peer;
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;

                // sock是面向字节流的,后续全部都是文件操作
                serviceIO(sock);
                close(sock); //不释放会出现文件描述符泄漏
            }
        }

        void serviceIO(int sock)
        {
            char buffer[1024];
            while (true)
            {
                ssize_t n = read(sock, buffer, sizeof(buffer) - 1);
                if (n > 0)
                {
                    buffer[n] = 0;
                    std::cout << "recv message: " << buffer << std::endl;

                    std::string outbuffer = buffer;
                    outbuffer += "server[echo]";

                    write(sock, outbuffer.c_str(), outbuffer.size());
                }
                else if (n == 0)
                {
                    // 代表client退出
                    logMessage(NORMAL, "client quit,me too");
                    break;
                }
            }
        }

        ~tcpServer()
        {
        }

    private:
        uint16_t _port;
        int _listensock; // 不是用来通信的,而是用于监听链接的
    };
}

1.成员函数

uint16_t _port:端口号

int _listensock:监听套接字

2.接口

1.initServer()创建套接字,先初始化监听套接字;生成对应的监听套接字;随后将当前的IP设置为任意IP,并且设置port最后绑定(bind)起来;随后还需要listen监听套接字

2.start()先定义新套接字,accept获取新套接字,执行套接字传输的任务。

start()实现方式
1.单一执行流
        void start()
        {
            for (;;)
            {
                // 1.sever获取新链接
                struct sockaddr_in peer;
                socklen_t len = sizeof peer;
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;

                // sock是面向字节流的,后续全部都是文件操作
                serviceIO(sock);
                close(sock); //不释放会出现文件描述符泄漏
            }
        }

这样的缺点很明显:只有一个执行流操作服务端,也就意味着客户端只有一个能链接服务端。而且serviceIO()是一个死循环函数,那么只有客户端主动退出才能让其他客户端链接。这是串行的执行逻辑

2.多进程
1.信号版
        void start()
        {
            signal(SIGCHLD, SIG_IGN);
            for (;;)
            {
                // 1.sever获取新链接
                struct sockaddr_in peer;
                socklen_t len = sizeof peer;
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;

                // 多进程
                pid_t id = fork();
                if (id == 0)
                {
                    // child
                    close(_listensock);
                    serviceIO(sock);
                    close(sock);
                    exit(0);
                }
                close(sock);
            }
        }

1.直接忽略子进程阻塞的状态,这样操作系统会自动回收

2.只要子进程自动回收,那么父进程就不需要等待,直接不断的按照需求新建子进程,而子进程执行结束不需要管理也不会有内存泄漏问题

3.在父进程处close(sock)的做法是为了不让文件描述符泄漏,子进程的close不影响父进程,如果父进程不弄,子进程把自己的套接字关闭不代表父进程的套接字也被关闭了

2.waitpid版
        void start()
        {
            for (;;)
            {
                // 1.sever获取新链接
                struct sockaddr_in peer;
                socklen_t len = sizeof peer;
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;

                // 多进程
                pid_t id = fork();
                if (id == 0)
                {
                    // child
                    close(_listensock);
                    if (fork() > 0)
                        exit;

                    // 孙子进程变为孤儿进程
                    serviceIO(sock);
                    close(sock);
                    exit(0);
                }
                close(sock);
                // father
                pid_t ret = waitpid(id, nullptr, 0); //子进程进去直接死亡回收,不需要管理
                if (ret > 0)
                    std::cout << "wait success: " << ret << std::endl;
            }
        }

1.父进程先非阻塞等待

2.子进程中创建孙子进程,孙子进程执行接收的文件,子进程直接退出,让父进程回收。此时孙子进程变成孤儿进程托付给操作系统,操作系统管理孙子进程的结束。

多进程展现的问题就是消费太多资源,本来一个执行流能解决的事情却创造了调度执行流的基本单位进程来实现,而且拷贝需要时间,成本过大。

3.多线程
    class ThreadData
    {
    public:
        ThreadData(tcpServer *self, int sock)
            : _self(self), _sock(sock)
        {
        }

    public:
        tcpServer *_self;
        int _sock;
    };

        void start()
        {
            for (;;)
            {
                // 1.sever获取新链接
                struct sockaddr_in peer;
                socklen_t len = sizeof peer;
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;

                // 多线程
                pthread_t tid;
                ThreadData *td = new ThreadData(this, sock);
                pthread_create(&tid, nullptr, threadRoutine, td);
            }
        }

        static void *threadRoutine(void *args)
        {
            pthread_detach(pthread_self());
            ThreadData *td = static_cast<ThreadData *>(args);

            td->_self->serviceIO(td->_sock);
            delete td;
            close(td->_sock);
            return nullptr;
        }

1.创造线程,让子线程进行接收执行。当然为了不需要串行执行,在threadRoutine()中,优先将当前线程进行线程分离。这样主线程就不需要回收子线程,子线程结束操作系统就会自动回收。

2.执行后需要将当前的文件描述符回收,由于函数是线程的公共资源,所以threadRoutine内就能影响到。

4.线程池
//线程池
using namespace ThreadNs;

const int gnum = 10;

template <class T>
class ThreadPool;

template <class T>
class ThreadData
{
public:
    ThreadData(ThreadPool<T> *tp, const std::string &n)
        : threadpool(tp), name(n)
    {
    }

public:
    ThreadPool<T> *threadpool;
    std::string name;
};

template <class T>
class ThreadPool
{
private:
    static void *handlerTask(void *args)
    {
        ThreadData<T> *td = static_cast<ThreadData<T> *>(args);
        while (true)
        {
            T t;
            {
                // td->threadpool->lockQueue();
                LockGuard lockguard(td->threadpool->mutex());
                while (td->threadpool->isQueueEmpty())
                {
                    td->threadpool->threadWait();
                }
                t = td->threadpool->pop();
            }
            // td->threadpool->unlockQueue();
            std::cout << td->name << "处理完了任务: " << t.toTaskString() << "并处理完成,结果是: " << t();
        }
        return nullptr;
    }

    ThreadPool(const int &_num = gnum)
        : _num(gnum)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; i++)
        {
            _threads.push_back(new Thread());
        }
    }

    void operator=(const ThreadPool &) = delete;

    ThreadPool(const ThreadPool &) = delete;

public:
    static ThreadPool<T> *getInstance()
    {
        if (_tp == nullptr)
        {
            _singleton_lock.lock();
            if (_tp == nullptr)
            {
                _tp = new ThreadPool<Task>();
            }
            _singleton_lock.unlock();
        }
        return _tp;
    }

    // void lockQueue()
    // {
    //     pthread_mutex_lock(&_mutex);
    // }

    // void unlockQueue()
    // {
    //     pthread_mutex_unlock(&_mutex);
    // }

    bool isQueueEmpty()
    {
        return _task_queue.empty();
    }

    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    T pop()
    {
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }

    pthread_mutex_t *mutex()
    {
        return &_mutex;
    }

public:
    void run()
    {
        for (const auto &t : _threads)
        {
            ThreadData<T> *td = new ThreadData<T>(this, t->threadname());

            t->start(handlerTask, td);
            std::cout << t->threadname() << " start ..." << std::endl;
        }
    }

    void push(const T &in)
    {
        // pthread_mutex_lock(&_mutex);
        LockGuard lockguard(&_mutex);
        _task_queue.push(in);
        pthread_cond_signal(&_cond);
        // pthread_mutex_unlock(&_mutex);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (const auto &t : _threads)
            delete t;
    }

private:
    int _num;
    std::vector<Thread *> _threads;
    std::queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *_tp;
    static std::mutex _singleton_lock;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
static std::mutex _singleton_lock;
/

        void start()
        {
            // 线程池初始化
            ThreadPool<Task>::getInstance()->run();
            for (;;)
            {
                // 1.sever获取新链接
                struct sockaddr_in peer;
                socklen_t len = sizeof peer;
                int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next"); // accept失败不影响整体的代码,继续访问即可
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;

                // 4.线程池
                ThreadPool<Task>::getInstance()->push(Task(sock, serviceIO));
            }
        }

3.main函数

using namespace std;
using namespace Server;

static void Usage(string proc)
{
    cout << "Usage:\n\t" << proc << " local_ip local_port\n\n";
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    std::unique_ptr<tcpServer> tsvr(new tcpServer(port));
    tsvr->initServer();
    tsvr->start();
    return 0;
}

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

1. 一旦启动,就会进入LISTEN状态

2.客户端

#define NUM 1024

namespace Client
{
    class tcpClient
    {
    public:
        tcpClient(const std::string &serverip, const uint16_t &serverport)
            : _serverip(serverip), _serverport(serverport), _sock(-1)
        {
        }

        void initClient()
        {
            // 1.创建socket
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock < 0)
            {
                std::cerr << "socket error: " << errno << " : " << strerror(errno) << std::endl;
                exit(2);
            }
            // 2.client要不要bind[必须要的],client要不要显示的bind,不需要
            // 3.客户端不需要listen
            // 4.也不需要accept
        }

        void start()
        {
            // 5.要发起链接
            struct sockaddr_in server;
            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());

            if (connect(_sock, (struct sockaddr *)&server, sizeof server) != 0)
            {
                std::cerr << "connect error: " << errno << " : " << strerror(errno) << std::endl;
            }
            else
            {
                std::string msg;
                while (true)
                {
                    std::cout << "Enter# ";
                    std::getline(cin, msg);
                    write(_sock, msg.c_str(), msg.size());

                    char buffer[NUM];
                    int n = read(_sock, buffer, sizeof(buffer) - 1);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        std::cout << "server回显的信息: " << buffer << std::endl;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        ~tcpClient()
        {
            if (_sock >= 0)
                close(_sock);
        }

    private:
        int _sock;
        std::string _serverip;
        uint16_t _serverport;
    };
}

1.成员函数

int _sock:套接字
std::string _serverip:server的IP地址
uint16_t _serverport:server发PORT

2.接口

3.mian函数

static void Usage(string proc)
{
    cout << "Usage:\n\t" << proc << " server_ip server_port\n\n";
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    uint16_t serverport = atoi(argv[2]);
    std::string serverip = argv[1];
    std::unique_ptr<tcpClient> tcli(new tcpClient(serverip, serverport));
    tcli->initClient();
    tcli->start();

    return 0;
}

在同一个服务器运行客户端和服务端

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

1.ESTABLISHED:指的是客户端被服务端所接收了

2.tcp的Server查到的是服务器的链接

3.tcp的Client查到的是客户端的链接

4.两端都是全双工的

3.守护进程化

1.守护进程

1.xshell在操作系统下会生成一个会话,此时bash充当前台任务,其他都是后台任务

2.前台任务有且只能有一个,而后台任务能允许有多个

3.所有的作业可以前后台转换。先fg转换,再ctrl+Z切换后台暂停,最后bg使得暂停任务重新开始

4.这些任务可能受到用户的登录和注销的影响的,我们需要将作业自称独立会话,和终端设备无关,这样的进程为守护进程

计算机网络(3) --- 网络套接字TCP,计算机网络,网络,计算机网络,tcp/ip,c++,linux

1.setsid:将非组员的进程独立成一个会话,并且该进程变成此会话的组长

2.不能是原先就是组长的进程

/dev/null:黑洞文件,信息重定向到该文件默认数据全部清空丢弃。

2.代码

#define DEV "/dev/null"

void daemonself(const char *currPath = nullptr)
{
    // 1.让调用进程忽略异常信号
    signal(SIGPIPE, SIG_IGN);

    // 2.如何让自己不是组长,setsid
    if (fork() > 0)
        exit(0);
    // 守护进程 -- 精灵进程,孤儿进程的一种
    pid_t n = setsid();
    assert(n != -1);

    // 3.守护进程脱离终端,关闭或者重定向以前进程默认打开文件 012
    int fd = open(DEV, O_RDWR);
    if (fd >= 0)
    {
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);

        close(fd);
    }
    else
    {
        close(0);
        close(1);
        close(2);
    }

    // 4.可选:进程执行路径发生变化
    if (currPath)
        chdir(currPath);
}

1.让调用进程忽略异常信号:不出现进程错误的问题使得守护过程终止

2.让自己不是组长(setsid):守护化的条件就是进程不能是会话的组长,要想不是,上面的处理方式是fork一个子进程,当前进程直接释放,使得fork的子进程变成孤儿进程,孤儿进程托付给操作系统,此时的组长是bash,那么就可以进行setsid了

3.守护进程脱离终端,关闭或者重定向以前进程默认打开文件 012:不直接关闭,将/dev/null这个黑洞文件重定向到012中。

4.可选:进程执行路径发生变化。将当前进程执行的路径换掉。

5.此时服务端的main函数逻辑为:文章来源地址https://www.toymoban.com/news/detail-633255.html

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    std::unique_ptr<tcpServer> tsvr(new tcpServer(port));
    tsvr->initServer();

    // 守护进程化
    daemonself();
    tsvr->start();
    return 0;
}

到了这里,关于计算机网络(3) --- 网络套接字TCP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【计算机网络】网络编程套接字(二)

    简单TCP服务器实现 我们将会使用到的头文件放在 comm.h 文件中 创建套接字 创建过程和UDP服务器几乎完全一样,除了使用的是TCP服务器使用的是流式服务(SOCK_STREAM),UDP使用的是数据包服务(SOCK_DGRAM) 服务器绑定 绑定的过程和UDP服务器也是相同的,可以看着复习一下 定义好 st

    2024年02月13日
    浏览(29)
  • 计算机网络(2) --- 网络套接字UDP

    计算机网络(1) --- 网络介绍_哈里沃克的博客-CSDN博客 https://blog.csdn.net/m0_63488627/article/details/131967378?spm=1001.2014.3001.5501 目录 1.端口号 2.TCP与UDP协议 1.TCP协议介绍 1.TCP协议 2.UDP协议 3.理解 2.网络字节序 发送逻辑 3.socket 1.介绍 2.sockaddr结构 4.UDP协议编程 1.接口介绍 1.创建套接字

    2024年02月14日
    浏览(33)
  • 【计算机网络】网络编程套接字(一)

    目录 1.预备知识 1.1.理解源IP地址和目的IP地址 1.2.认识端口号 1.2.1.理解\\\"端口号\\\"和\\\"进程ID\\\" 1.2.2.理解源端口号和目的端口号 1.3.认识TCP/UDP协议 1.3.1.TCP协议 1.3.2.UDP协议 1.4.网络字节序 网络字节序和主机字节序的转换 2.socket编程接口 2.1.sockaddr结构 struct sockaddr_in 的具体结构: 2.

    2024年02月08日
    浏览(34)
  • 计算机网络---网络编程套接字(一)

    ✨ 计算机网络—网络编程套接字之UDP数据报套接字编程 作者介绍: 🎓作者:偷偷敲代码的青花瓷🐱‍🚀 👀作者的Gitee:代码仓库 📌系列文章推荐:计算机网络 ——网络原理之初识 ✨✨我和大家一样都是热爱编程✨,很高兴能在此和大家分享知识,希望在分享知识的同时,能和大

    2023年04月09日
    浏览(25)
  • 计算机网络 | socket IPC(本地套接字domain)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《Linux从小白到大神》《网络编程》 soc

    2024年02月08日
    浏览(28)
  • 【计算机网络】网络编程套接字&UDP服务器客户端的简单模拟

    需要云服务器等云产品来学习Linux的同学可以移步/–腾讯云–/官网,轻量型云服务器低至112元/年,优惠多多。(联系我有折扣哦) 每台主机都有自己的IP地址,当数据在进行通信的时候,除了要发送的数据外,在报头里面还要包含发送方的IP和接收方的IP,这里发送方的IP就

    2024年02月20日
    浏览(32)
  • 【JavaEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月20日
    浏览(41)
  • 【JaveEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月13日
    浏览(39)
  • 网络编程套接字( TCP )

    目录 1、实现一个TCP网络程序(单进程版)         1.1、服务端serverTcp.cc文件                  服务端创建套接字                  服务端绑定                  服务端监听                  服务端获取连接                  服务

    2024年01月17日
    浏览(36)
  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包