TCP套接字相关知识

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

TCP特有的相关接口

listen接口

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd,int backlog);

返回值

成功 0被返回
失败 -1被返回

accept接口

#include <sys/types.h>
#include <sys/socket.h>

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

 返回值

返回文件描述符

connect接口

#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);

 返回值 

成功 0被返回。
失败 -1被返回。
并且在connect的时候返回成功自定bind。

普通版本代码

服务端

套接字的创建

// 1. 创建socket文件套接字对象
_listensock = socket(AF_INET, SOCK_STREAM, 0);
if (_listensock < 0)
{
    logMessage(FATAL, "create socket error");
    exit(SOCKET_ERR);
}
logMessage(NORMAL, "create socket success");

 bind连接

// 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 socket error");
    exit(BIND_ERR);
}
logMessage(NORMAL, "bind socket success");

 listen监听接口

TCP是面向连接的所以需要将套接字设置为监听状态


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

客户端在何时连接? 

 客户端连接服务端的时候,服务端需要就可以accept到客户端发来的信息。

accept接口

// 4. server 获取新链接
// sock 和客户端进行通信的fd
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");
    cout << "sock: " << sock << endl;

    continue;
}
logMessage(NORMAL, "accept a new link success,get new sock: %d", sock);

serviceIO 服务端的服务

先读后写

void serviceIO(int sock)
{
    char buffer[1024];
    while (true)
    {
        size_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;
        }
    }
    close(sock);
}

客户端代码

创建套接字


// 1. 创建socket
_sock = socket(AF_INET, SOCK_STREAM, 0);
if (_sock < 0)
{
    cerr << "socket create error" << endl;
}

// 2. tcp的客户端要不要bind? 要的 要不要显示的bind?
// 不要! 这里尤其是client port要让OS自定随机自定!
// 3. 要不要listen?不要!只有服务端需要!
// 4. 要不要accept?不要!只有服务端需要!
// 5. 要什么呢??要发起链接!

 链接  发送数据


void start()
{
    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());

    int con = connect(_sock, (struct sockaddr *)&server, sizeof(server));
    if (con != 0)
    {
        cerr << "socket connect error" << endl;
    }
    else
    {
        string msg;
        while (true)
        {
            cout << "Enter# ";
            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;
                cout << "Server回显# " << buffer << endl;
                buffer[0] = 0;
            }
            else
            {
                break;
            }
        }
    }
}

普通版本完整代码

makefile

cc=g++

.PHONY:all
all:tcpclient tcpserver

tcpclient:tcpClient.cc
	$(cc) -o $@ $^ -std=c++11

tcpserver:tcpServer.cc
	$(cc) -o $@ $^ -lpthread -std=c++11

.PHONY:clean
clean:
	rm -f tcpclient tcpserver

tcpserver.hpp


#pragma once
#include <iostream>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include "log.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"
using namespace std;

namespace server
{

    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };

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

    class TcpServer;

    class ThreadData
    {
    public:
        ThreadData(TcpServer *self, int sock)
            : _self(self), _sock(sock)
        {
        }
        ~ThreadData()
        {
        }
        TcpServer *_self;
        int _sock;
    };

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

            // 1. 创建socket文件套接字对象
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensock < 0)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create socket 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 socket error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "bind socket success");

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

        void start()
        {
            for (;;)
            {
                // 4. server 获取新链接
                // sock 和客户端进行通信的fd
                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");
                    cout << "sock: " << sock << endl;

                    continue;
                }
                // logMessage(NORMAL, "accept a new link success,get new sock: %d", sock);
                logMessage(NORMAL, "accept a new link success");
                cout << "sock: " << sock << endl;

                    // 5. 这里就是一个sock,未来通信我们就用这个sock,面向字节流的,后续全部都是文件操作!

                    // version 1
                    serviceIO(sock);
                close(sock); // 对一个就已经使用完毕的sock,我们要关闭这个sock
                // 要不然会导致。
                // version 多进程版 多线程版 线程池版

                
            }
        }

       

        void serviceIO(int sock)
        {
            char buffer[1024];
            while (true)
            {
                ssize_t n = read(sock, buffer, sizeof(buffer) - 1);
                if (n > 0)
                {
                    // 目前我们把读的数据当成字符串,截止目前
                    buffer[n] = 0;
                    cout << "recv message: " << buffer << endl;

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

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

    private:
        int _listensock; // 不是用来进行数据通信的,它是用来监听链接到来,获取新链接的!
        uint16_t _port;
    };
}

tcpserver.cc

#include "tcpServer.hpp"
#include "daemon.hpp"
#include <memory>

using namespace server;
using namespace std;

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

// tcp服务器,启动上和udp server一模一样
// ./tcpServer local_port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=atoi(argv[1]); // 字符串转整型

    unique_ptr<TcpServer> tsvr(new TcpServer(port));

    tsvr->initServer();
    // daemonSelf();
    tsvr->start();



    return 0;
}

tcpclient.hpp

#pragma once

#include <iostream>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

using namespace std;

#define NUM 1024

class TcpClient
{
public:
    TcpClient(const string &serverip, const uint16_t &serverport)
        : _sock(-1), _serverip(serverip), _serverport(serverport)
    {
    }
    void initClient()
    {
        // 1. 创建socket
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            cerr << "socket create error" << endl;
        }
        // 2. tcp的客户端要不要bind? 要的 要不要显示的bind?
        // 不要! 这里尤其是client port要让OS自定随机自定!
        // 3. 要不要listen?不要!只有服务端需要!
        // 4. 要不要accept?不要!只有服务端需要!
        // 5. 要什么呢??要发起链接!
    }

    void start()
    {
        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());


        int con = connect(_sock, (struct sockaddr *)&server, sizeof(server));
        if (con != 0)
        {
            cerr << "socket connect error" << endl;
        }
        else
        {
            string msg;
            while (true)
            {
                cout << "Enter# ";
                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;
                    cout << "Server回显# " << buffer << endl;
                    buffer[0] = 0;
                }
                else
                {
                    break;
                }
            }
        }
    }
    ~TcpClient()
    {
        if (_sock >= 0)
        {
            close(_sock);
        }
    }

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

tcpclient.cc

#include "tcpClient.hpp"
#include <memory>

using namespace std;

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

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

    string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);

    unique_ptr<TcpClient> tcli(new TcpClient(serverip, serverport));

    tcli->initClient();
    tcli->start();

    return 0;
}


// log.hpp

#pragma once

#include <iostream>
#include <string>
#include <stdarg.h>
#include <time.h>
#include <unistd.h>

using namespace std;

void logMessage(int level, const char *message)
{
    cout << message << endl;
}

多进程版本

版本一

孙子进程进行提供服务

// 多进程版本1
// version 2
pid_t id = fork();

if (id == 0) // child
{
    close(_listensock); // 子进程中不需要监听因此关闭监听的文件描述符
    if (fork() > 0)
        exit(0);

    serviceIO(sock);
    close(sock);
    exit(0);
}

// father
pid_t ret = waitpid(id, nullptr, 0);

if (ret > 0)
{
    cout << "waitsuccess: " << ret << endl;
}

版本二

通过屏蔽信号SIGCHLD来防止僵尸进程

// 多进程版本2
signal(SIGCHLD, SIG_IGN);

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

多线程版本

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;
}

pthread_t tid;
ThreadData *td = new ThreadData(this, sock);
pthread_create(&tid, nullptr, threadRoutine, td);

线程池版本

线程池初始化

ThreadPool<Task>::getInstance()->run();

线程池

ThreadPool<Task>::getInstance()->push(Task(sock, serviceIO));
####################################
Task.hpp
####################################

#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <cstdio>

void serviceIO(int sock)
{
    char buffer[1024];
    while (true)
    {
        size_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;
        }
    }
    close(sock);
}

// 计算数据的类
class Task
{
    using func_t = std::function<void(int)>;

public:
    Task()
    {
    }

    Task(int sock, func_t func)
        : _sock(sock), _callback(func)
    {
    }

    // 该函数是消费任务的打印信息
    void operator()()
    {
        _callback(_sock);
    }

private:
    int _sock;
    func_t _callback;
};

####################################
ThreadPool.hpp
####################################

#pragma once

#include "Thread.hpp"
#include "LockGuard.hpp"
#include "log.hpp"
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include <mutex>

using namespace ThreadNs;

const int gnum = 10;

template <class T>
class ThreadPool;

template <class T>
class ThreadData
{
public:
    ThreadPool<T> *threadpool;
    std::string name;

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

template <class T>
class ThreadPool
{
private:
    static void *handlerTask(void *args)
    {
        ThreadData<T> *td = (ThreadData<T> *)args;
        while (true)
        {
            T t;
            {
                LockGuard lockguard(td->threadpool->mutex());

                while (td->threadpool->isQueueEmpty())
                {
                    td->threadpool->threadWait();
                }

                // pop的本质,是将任务从公共的队列当中,拿到当前线程自己独立的栈中
                t = td->threadpool->pop();
            }
            t();
        }
        delete td;
        return nullptr;
    }
    // 单例模式:构造函数设置为私有
    ThreadPool(const int &num = gnum) : _num(num)
    {
        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;

    // 为了解决static handlerTask
public:
    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;
            // logMessage(DEBUG, "%s start ...", t->threadname().c_str());
        }
    }

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

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);

        for (const auto &t : _threads)
            delete t;
    }

    static ThreadPool<T> *getInstance()
    {
        // 最外边这个if的作用是:
        // 如果tp已经被创建,那么就不用创建了,因为是单例模型
        if (nullptr == tp)
        {
            _singlock.lock();
            if (nullptr == tp)
            {
                tp = new ThreadPool<T>();
            }
            _singlock.unlock();
        }

        return tp;
    }

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 _singlock;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::tp = nullptr;

template <class T>
std::mutex ThreadPool<T>::_singlock;

日志


#pragma once

#include <iostream>
#include <string>
#include <stdarg.h>
#include <time.h>
#include <unistd.h>

using namespace std;

#define LOG_NORMAL "log.txt"
#define LOG_ERR "log.error"

#define DEBUG 0
#define NORMAL 1
#define WRNING 2
#define ERROR 3
#define FATAL 4

// 根据不同的日志等级来返回不同的日志信息
const char *to_levelstr(int level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
    case NORMAL:
        return "NORMAL";
    case WRNING:
        return "WRNING";
    case ERROR:
        return "ERROR";
    case FATAL:
        return "FATAL";
    default:
        return nullptr;
    }
}
// [日志等级] [时间戳/时间] [pid] [message]
// [WARNING] [2023-6-29 8:25:08] [123] [创建socket失败]

// va_list start;

// start 指针

// va_start(start); -- 把start指向第一个

// va_arg(start,float); 让这个指针向后移动指定类型的大小

// va_end(start); 让start这个指针设为NULL
// while (*p)
// {
//     switch (*p)
//     {
//     case '%':
//         p++;
//         if (*p == 'f')
//             arg = va_arg(start, float);
//         // ...
//     }
// }
// va_end(start);

// void logMessage(DEBUG, "hello %f, %d, %c",3.14,10,'C');
void logMessage(int level, const char *format, ...)
{
#define NUM 1024
    char logprefix[NUM];
    // logprefix
    // [日志等级] [时间戳/时间] [pid] 
    snprintf(logprefix, sizeof(logprefix), "[%s][%ld][pid: %d]",
             to_levelstr(level), (long int)time(nullptr), getpid());

    char logcontent[NUM];
    va_list arg;
    va_start(arg, format);
    // [message]
    vsnprintf(logcontent, sizeof(logcontent), format, arg);

    cout << logprefix << logcontent << endl;

    FILE *log = fopen(LOG_NORMAL, "a");
    FILE *err = fopen(LOG_ERR, "a");

    if (log != nullptr && err != nullptr)
    {
        FILE *curr = nullptr;
        if (level == DEBUG || level == NORMAL || level == WRNING)
            curr = log;
        if (level == ERROR || level == FATAL)
            curr = err;
        if (curr)
            fprintf(curr, "%s%s\n", logprefix, logcontent);

        fclose(log);
        fclose(err);
    }
}

守护进程

解析

不受用户登录注销的进程。文章来源地址https://www.toymoban.com/news/detail-527348.html

setsid 接口

#include <unistd.h>

pid_t setsid(void);

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

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

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

相关文章

  • 【Linux网络编程】网络编程套接字(TCP服务器)

    作者:爱写代码的刚子 时间:2024.4.4 前言:本篇博客主要介绍TCP及其服务器编码 只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP地址 但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换 字符串转in

    2024年04月14日
    浏览(79)
  • 【Linux网络】网络编程套接字(预备知识+UDP)

    目录 预备知识 1. 理解源IP地址和目的IP地址 2. 理解源MAC地址和目的MAC地址 3. 认识端口号  4. 理解源端口号和目的端口号 5. 端口号(port) vs 进程pid 6. 认识TCP协议和认识UDP协议 7. 网络字节序 socket编程接口  1. socket 常见API 2. sockaddr结构  简单的UDP网络程序  1. 服务端创建udp

    2024年02月19日
    浏览(58)
  • 【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)

    在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。 本文将延续上文内容,重点讨论简单的TCP网络程序模拟实现 。通过本文的学习,读者将能够深入了解TCP协议的实际应用,并掌握如何编写简单的TCP网络程序。让我们一起深入探讨TCP网络程序的

    2024年04月14日
    浏览(87)
  • 【探索Linux】P.25(网络编程套接字基本概念 —— 预备知识)

    在上一篇文章中,我们深入探讨了Linux网络的基础知识和它的发展历史,为读者揭开了Linux网络技术演变的序幕。我们了解到,Linux网络技术的发展不仅促进了操作系统本身的成熟,还对整个互联网的进步产生了深远的影响。随着网络技术的不断进步,Linux系统在网络通信方面

    2024年04月27日
    浏览(49)
  • 【Linux】TCP网络套接字编程+协议定制+序列化和反序列化

    悟已往之不谏,知来者之可追。抓不住的就放手,属于你的都在路上…… 1. 为了让我们的代码更规范化,所以搞出了日志等级分类,常见的日志输出等级有DEBUG NORMAL WARNING ERROR FATAL等,再配合上程序运行的时间,输出的内容等,公司中就是使用日志分类的方式来记录程序的输

    2024年02月08日
    浏览(70)
  • 网络编程套接字应用分享【Linux &C/C++ 】【UDP应用 | TCP应用 | TCP&线程池小项目】

    目录 前提知识 1. 理解源ip,目的ip和Macip 2. 端口号 3. 初识TCP,UDP协议 4. 网络字节序 5. socket 编程 sockaddr类型  一,基于udp协议编程  1. socket——创建套接字 2. bind——将套接字强绑定  3. recvfrom——接受数据 4. sendto——发出信息  遇到的问题 (1. 云服务器中以及无法分配I

    2024年04月08日
    浏览(91)
  • [Linux] 网络编程 - 初见TCP套接字编程: 实现简单的单进程、多进程、多线程、线程池tcp服务器

    网络的上一篇文章, 我们介绍了网络变成的一些重要的概念, 以及 UDP套接字的编程演示. 还实现了一个简单更简陋的UDP公共聊天室. [Linux] 网络编程 - 初见UDP套接字编程: 网络编程部分相关概念、TCP、UDP协议基本特点、网络字节序、socket接口使用、简单的UDP网络及聊天室实现…

    2024年02月16日
    浏览(66)
  • 【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日
    浏览(75)
  • 【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日
    浏览(169)
  • 「网络编程」第二讲:socket套接字(四 - 完结)_ Linux任务管理与守护进程 | TCP协议通讯流程

    「前言」文章是关于网络编程的socket套接字方面的,上一篇是网络编程socket套接字(三),这篇续上篇文章的内容,下面开始讲解!  「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 Time goes on and on, never to an 

    2024年02月10日
    浏览(65)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包