Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >网络编程 - Linux Socket编程

网络编程 - Linux Socket编程

作者头像
开源519
发布于 2023-03-09 07:07:56
发布于 2023-03-09 07:07:56
10.1K00
代码可运行
举报
文章被收录于专栏:开源519开源519
运行总次数:0
代码可运行

Linux Socket编程


目录

  • 前言
  • Socket的功能
  • Socket基础
    • Socket类型
    • 基本结构
    • 基本转换函数
  • 基本Socket使用
  • TCP Socket实例
  • UDP Socket实例
  • 疑难问题记录
  • 总结

前言

  socket(套接字)是网络编程编程的一种技巧。通过socket不仅可以实现跨进程通信,还可以实现跨主机的网络通信。使用这种技术,就可以实现全国各地的通讯。例如:深圳的一台电脑接收来自北京一台电脑发来的信息。   本篇不涉及太底层的网络原理,仅说明socket的基本使用方法。主要参考《Linux网络编程》。本篇源码获取方式见文底小字。

Socket的功能

  socket是通过标准的UNIX文件描述符和其他的程序通讯的一个方法。其可以实现同一主机不同进程间的通信;也可以实现不同主机间的通信。

Socket基础

Socket类型

  套接字有三种类型:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)和原始套接字。

流式套接字(SOCK_STREAM)   流式的套接字可以提供可靠的、面向连接的通讯流。如果你通过流式套接字发送了顺序的数据:"1"、"2"。那么数据到达远程时候的顺序也是"1"、"2"。

面向连接的Socket工作流程

数据报套接字(SOCK_DGRAM)   数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。

原始套接字(SOCK_RAM)   原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。

基本结构

  • struct sockaddr 此结构用于存储套接字地址。在需要通信地址时,此结构体会被用到,例如connect()
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct sockaddr {
    unsigned short sa_family; /* address族, AF_xxx */
    char sa_data[14];         /* 14 bytes的协议地址 */
};

sa_family为指定协议族,通常使用到的有AF_INET、AF_UNIX等。 sa_data为不同协议族通信时必要的数据。例如,sa_family为AF_INET时,sa_data要传IP地址和端口号。

  • struct sockaddr_in sockaddr_in是用于存储AF_INET的套接字地址,其中in就代表Inet。   介绍sockaddr时,说到在使用AF_INET需要传IP和端口号,但并不知道要将IP和端口号填到sockaddr的哪个地方。于是,设计了sockaddr_in,定义出地址和端口号成员。在使用时只需要填充sockaddr_in,传参时强转为sockaddr即可(两个结构体大小一致)。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct sockaddr_in {
    short int sin_family;        /* Internet地址族 */
    unsigned short int sin_port; /* 端口号 */
    struct in_addr sin_addr;     /* Internet地址 */
    unsigned char sin_zero[8];   /* 添0(和struct sockaddr一样大小) */
};
  • struct in_addr in_addrsockaddr_in成员,用于存储4个字节的IP地址。需要注意的是,此值填写时需要按照网络字节来填充,可以通过一些转换函数完成。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct in_addr {
    unsigned long s_addr;
};
  • struct sockaddr_un sockaddr_un是用于存储AF_UNIX的套接字地址,推测un就代表UNIX(没有求证)。   和上述类似,当使用AF_UNIX时,需要填充AF_UNIX的地址结构体sockaddr_un,然后传参时强转为sockaddr
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct sockaddr_un
{
    uint8_t sun_len;
    sa_family_t sun_family;  /* AF_LOCAL */
    char sun_path[104];      /* null-terminated pathname */
};

基本转换函数

网络字节序转换   上文描述填写IP和端口时要注意网络字节序,否则可能连接不到指定的设备。系统提供了如下几种函数方便转换:

  • htons()—— “Host to Network Short” 主机字节顺序转换为网络字节顺序(对无符号短型进行操作 4 bytes)
  • htonl()—— “Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符号长型进行操作 8 bytes)
  • ntohs()—— “Network to Host Short” 网络字节顺序转换为主机字节顺序(对无符号短型进行操作 4 bytes)
  • ntohl()—— “Network to Host Long” 网络字节顺序转换为主机字节顺序(对无符号长型进行操作 8 bytes)

IP地址转换

  • inet_addr()—— 把一个用数字和点表示 IP 地址的字符串转换成网络字节序的无符号长整型。
  • inet_ntoa()—— “Network to ASCII” 将网络字节序的长整型转换成字符串。

inet_ntoa()返回一个字符指针,它指向一个定义在函数 inet_ntoa() 中的 static 类型字符串。所以每次调用 inet_ntoa(),都会改变最后一次调用 inet_ntoa() 函数时得到的结果。

基本Socket使用

  Linux同时支持面向连接和不连接类型的套接字。在面向连接的通讯中服务器和客户机在交换数据之前先要建立一个连接;在不连接通讯中数据被作为信息的一部分被交换。   无论那一种方式,服务器总是最先启动,把自己绑定(Banding)在一个套接字上,然后侦听信息。

socket主要使用到如下函数:

  • socket()函数 —— 创建套接字。
  • bind()函数 —— 绑定socket地址信息。(Inet需要传入IP、端口;Unix 需要传入路径)
  • connect()函数 —— 连接指定服务器套接字。
  • listen()函数 —— 服务器监听连接上的套接字客户端。
  • accept()函数 —— 接受远程客户端套接字,会获取到远程连接客户端的地址信息。(阻塞接口)
  • send()函数/recv()函数 —— 连接的流式套接字进行通讯的函数。
  • sendto()函数/recvfrom()函数 —— 非连接的数据报套接字进行通讯的函数。
  • close()函数 —— 关闭套接字描述符所表示的连接。
  • shutdown()函数 —— 指定关闭套接字的方式。
  • setsockopt()函数/getsockopt()函数 —— 套接字设置项的设置和获取。
  • getpeername()函数 —— 取得一个已经连接上的套接字的远程信息。
  • getsockname()函数 —— 取得本地主机的信息。
  • gethostbyname()函数 —— 通过域名获取IP地址。
  • gethostbyaddr()函数 —— 通过一个IPv4的地址来获取主机信息。
  • getprotobyname()函数 —— 获得网络协议名。

TCP Socket实例

  TCP Socket可以理解为Inet使用流式套接字,为保证通讯稳定而采用TCP协议。其优点在于可靠、稳定。

TCP Socket 服务端

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void DealClientMsgThread(int fd)
{
    while(1)
    {
        char buf[1024] = {0};
        int ret = read(fd, buf, sizeof(buf));
        if (ret > 0) {
            TSVR_LOG("# RECEIVE: %s.\n", buf);

            // response dstAddr msg
            char ack[20] = {0};
            snprintf(ack, sizeof(ack), "Ack [%ld]", strlen(buf));
            write(fd, ack, strlen(ack));
        } else {
            break;
        }
    }
    
    TSVR_LOG("Disconnect.\n");
}

int main(int argc, char *argv[])
{
    int i = 0;
    std::thread threads[MAX_NUM_THREAD];

    if (argc != 2)
    {
        TSVR_LOG("usage ./tcp_server 8080.\n");
        return -1;
    }

    string port = argv[1];

    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockFd == -1)
    {
        TSVR_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }

    int op = 1;
    if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0) {
        TSVR_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        goto exit;
    }

    struct sockaddr_in myAddr;
    bzero(&myAddr, sizeof(myAddr));
    myAddr.sin_family = AF_INET;
    myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myAddr.sin_port = htons(atoi(port.c_str()));
    if (bind(sockFd, (struct sockaddr *)&myAddr, sizeof(myAddr)) == -1) {
        TSVR_LOGE("bind failed. (%s)", strerror(errno));
        goto exit;
    }

    if (listen(sockFd, MAX_SIZE_BACKLOG) == -1) {
        TSVR_LOGE("listen failed. (%s)\n", strerror(errno));
        goto exit;
    }

    while(1)
    {
        // accept
        struct sockaddr_in dstAddr;
        socklen_t addrSize = (socklen_t)sizeof(dstAddr);
        int conFd = accept(sockFd, (struct sockaddr *)&dstAddr, &addrSize);
        if (conFd < 0) {
            TSVR_LOGE("accept failed. (%s)\n", strerror(errno));
            continue;
        }
        
        if (i < MAX_NUM_THREAD)
        {
            threads[i] = std::thread(DealClientMsgThread, conFd);
            threads[i].detach();
            i++;
        } else {
            TSVR_LOG("The number of threads reaches max(%d).\n", MAX_NUM_THREAD);
        }
    }

exit:
    close(sockFd);
    return 0;
}

TCP Socket 客户端

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char *argv[])
{
    int op = 1024;

    if (argc != 3)
    {
        TCLT_LOG("usage ./tcp_client <ip> <port>.\n");
        return -1;
    }

    string ipAddr = argv[1];
    string port = argv[2];

    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockFd == -1)
    {
        TCLT_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }

    if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &op, sizeof(op)) < 0) {
        TCLT_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        close(sockFd);
        return -1;
    }

    if (setsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, &op, sizeof(op)) < 0) {
        TCLT_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        close(sockFd);
        return -1;
    }

    struct sockaddr_in dstAddr;
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str());
    dstAddr.sin_port = htons(atoi(port.c_str()));
    // Linux TCP repeat connect directly return EISCONN.
    if (   connect(sockFd, (struct sockaddr*)&dstAddr, sizeof(struct sockaddr_in)) < 0 
        && errno != EISCONN) 
    {
        TCLT_LOGE("connect %s:%d failed. (%s)\n", ipAddr.c_str(), atoi(port.c_str()), strerror(errno));
        close(sockFd);
        return -1;
    }

    thread rTh([&]() {
        char recvBuf[1024] = {0};
        TCLT_LOG("Start write thread.\n");

        while(1)
        {
            int ret = read(sockFd, recvBuf, sizeof(recvBuf));
            if (ret > 0) {
                TCLT_LOG("# RECEIVE: %s.\n", recvBuf);
            } else {
                break;
            }
        }
    });
    
    thread wTh([&]() {
        TCLT_LOG("Start read thread.\n");

        while(1)
        {
            char sndBuf[] = "Hello World";
            int ret = write(sockFd, sndBuf, strlen(sndBuf));
            if (ret > 0)
            {
                TCLT_LOG("# SEND > %s.\n", sndBuf);
            } else {
                break;
            }
            sleep(2);
        }
    });
    
    rTh.join();
    wTh.join();

    return 0;
}

代码是很简单的TCP通讯处理,为方便理解,不做过多封装。

UDP Socket实例

  UDP Socket可以理解为Inet使用数据报套接字,为了快速通讯,客户端与服务端约定采用的UDP的套接字通讯。

UDP Socket 服务端

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char *argv[])
{
    struct sockaddr_in dstAddr;
    socklen_t addrSize = sizeof(struct sockaddr_in);

    if (argc != 2)
    {
        USVR_LOG("usage ./udp_server 8080.\n");
        return -1;
    }
    
    string port = argv[1];

    int sockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockFd == -1)
    {
        USVR_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }
    
    int op = 1;
    if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0) {
        USVR_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        goto exit;
    }

    struct sockaddr_in myAddr;
    bzero(&myAddr, sizeof(struct sockaddr_in));
    myAddr.sin_family = AF_INET;
    myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myAddr.sin_port = htons(atoi(port.c_str()));
    if (bind(sockFd, (struct sockaddr *)&myAddr, sizeof(struct sockaddr_in)) < 0) {
        USVR_LOGE("bind failed. (%s)\n", strerror(errno));
        goto exit;
    }

    while(1)
    {
        char buf[1024] = {0};
        int ret = recvfrom(sockFd, buf, sizeof(buf), 0, 
                    (struct sockaddr *)&dstAddr, &addrSize);

        if (ret > 0) {
            char ack[20] = {0};

            snprintf(ack, sizeof(ack), "Ack [%ld]", strlen(buf));
            USVR_LOG("# RECEIVE: %s.\n", buf);
            sendto(sockFd, ack, strlen(ack), 0, 
                    (struct sockaddr *)&dstAddr, addrSize);

        } else {
            USVR_LOG("recvfrom failed. (%s)\n", strerror(errno));
            break;
        }
    }

exit:
    close(sockFd);
    return 0;
}

UDP Socket 客户端

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        UCLT_LOG("usage ./udp_client <ip> <port>.\n");
        return -1;
    }

    string ipAddr = argv[1];
    string port = argv[2];

    int sockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockFd == -1)
    {
        UCLT_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }

    int op = 1024;
    if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &op, sizeof(op)) < 0) {
        UCLT_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        close(sockFd);
        return -1;
    }

    struct sockaddr_in dstAddr;
    bzero(&dstAddr, sizeof(struct sockaddr_in));
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str());
    dstAddr.sin_port = htons(atoi(port.c_str()));

    thread wTh([&]() {
        UCLT_LOG("Start write thread.\n");

        while(1)
        {
            char sndBuf[] = "Hello World";
            int ret = sendto(sockFd, sndBuf, strlen(sndBuf), 0, 
                        (struct sockaddr *)&dstAddr, sizeof(struct sockaddr_in));

            if (ret > 0) {
                UCLT_LOG("# SEND: %s.\n", sndBuf);
            } else {
                break;
            }

            sleep(2);
        }
    });
    
    thread rTh([&]() {
        struct sockaddr_in dstAddr;
        UCLT_LOG("Start read thread.\n");

        while(1)
        {
            char recvBuf[1024] = {0};
            socklen_t addrSize = sizeof(struct sockaddr_in);
            bzero(&dstAddr, addrSize);
            int ret = recvfrom(sockFd, recvBuf, sizeof(recvBuf), 0, 
                        (struct sockaddr *)&dstAddr, &addrSize);

            if (ret > 0)
            {
                UCLT_LOG("# RECEIVE: %s.\n", recvBuf);
            } else {
                break;
            }
        }
    });
    
    wTh.join();
    rTh.join();
    return 0;
}

疑难问题记录

  • TCP服务端和客户端如何精确地检测到对方下线或异常断开? ① 接收函数是阻塞的,当对方断开,接收函数会返回异常。 ② 通过错误码和信号判断,当一端异常断开,另一端会收到SIGPIPE信号,再通过getsockopt查询各个套接字确认哪一个断开。
  • UDP 如何保证通讯数据稳定 UDP通讯因为不需要连接,从而比TCP通讯更快,但是由于其不确保数据是否安全到达,从而显得不靠谱。为了实现通讯靠谱,需要在应用层建立一套机制验证数据准确性,建立失误重传的约定。

总结

  • socket的实现非常优秀,将复杂的网络通信,封装成简单的socket的接口。使用者不用过多考虑TCP、UDP以及其他较底层的网络概念,而快速的实现一套网络通讯的流程。
  • 本文仅列举了socket用于inet地址族的例程,其还可以用于UNIX域的进程间通讯。
  • 网络编程非常有趣,能够实现天南海北之间的通讯,让远距离的人与人、人与物或者物与物之间产生联系,很有意思!

最后

用心感悟,认真记录,写好每一篇文章,分享每一框干货。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源519 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
linux网络编程之socket(三):最简单的回射客户/服务器程序、time_wait 状态
s1mba
2017/12/28
1.5K0
linux网络编程之socket(三):最简单的回射客户/服务器程序、time_wait 状态
【Linux】:Socket编程 TCP
在上篇文章里面已经讲了关于 Socket UDP 网络编程的内容,这篇文章我们主要是关于 Socket TCP 网络编程的内容
IsLand1314
2025/01/20
4460
【Linux】:Socket编程 TCP
Socket编程---UDP篇
但是,并不是说,TCP就是百利而无一害的。前面说了,TCP还有一个特性---面向字节流,这就导致了,目标主机读取到的内容可能并不是完整的源主机发送的内容。后续讲TCP实现的时候会体现出来。
小灵蛇
2024/09/08
3930
Socket编程---UDP篇
Socket编程实践(2) Socket API 与 简单例程
在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程。该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端。 socket()函数 socket()函数用于创建一个套接字。这就好像购买了一个电话。不过该电话还没有分配号码。 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol
Tencent JCoder
2018/07/02
8780
Linux下Socket编程入门
网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节序采用big endian排序方式。
_咯噔_
2022/02/23
3.8K0
【Linux网络】Linux网络编程套接字,UDP与TCP
前言:在当今这个信息技术日新月异的时代,网络编程已成为连接世界、构建各类互联网应用不可或缺的一部分。而Linux,作为开源操作系统的典范,其强大的网络功能和灵活性,为开发者们提供了一个广阔而深入的实践平台。在众多网络编程技术中,套接字(Socket)编程无疑是核心与基石,它不仅支撑着Web服务、即时通讯、在线游戏等日常应用,还是实现分布式系统、云计算服务的关键技术之一。
Eternity._
2024/11/18
4510
【Linux网络】Linux网络编程套接字,UDP与TCP
Udp协议Socket编程
  本次socket编程需要使用到 日志文件,此为具体日志编写过程。以及 线程池,线程池原理比较简单,看注释即可。
用户11029129
2024/11/17
1330
Udp协议Socket编程
【在Linux世界中追寻伟大的One Piece】Socket编程TCP
由于客户端不需要固定的端口号,因此不必调用bind(),客户端的端口号由内核自动分配。
枫叶丹
2024/11/03
1070
【在Linux世界中追寻伟大的One Piece】Socket编程TCP
温故Linux后端编程(五):SOCKET网络编程
struct sockaddr :很多网络编程函数的出现早于IPV4协议,为了向前兼容,现在sockaddr都退化成(void *)结构了。 传递一个地址给函数,然后由函数内部再强制类型转换为所需的地址类型。
看、未来
2021/09/18
9050
linux下Socket编程(一)简介
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现, socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。 说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 注意: 其实socket也没有层的概念,它只是一个facade设计模式的应用,让编程变的更简单。是一个软件抽象层。在网络编程中,我们大量用的都是通过socket实现的。
用户2929716
2018/08/23
3.7K0
linux下Socket编程(一)简介
基于udp的socket编程 c语言_C语言编程游戏
UDP协议的程序设计框架,客户端和服务器之间的差别在于服务器必须使用bind()函数来绑定侦听的本地UDP端口,而客户端则可以不进行绑定,直接发送到服务器地址的某个端口地址。框图如图1.3所示
全栈程序员站长
2022/10/04
19.5K0
基于udp的socket编程 c语言_C语言编程游戏
【Linux网络编程】Socket编程--UDP(第一弹):实现客户端和服务器互相发送消息
任何一个UDP服务通信中,都需要有一个int sockfd的文件描述符,按照系统编程中所说,这里打印出来的文件描述符应该是3,因为0,1,2已经被占用了。
南桥
2024/10/20
2530
【Linux网络编程】Socket编程--UDP(第一弹):实现客户端和服务器互相发送消息
【C++】基础:网络编程介绍与TCP&UDP示例
网络传输模型可以抽象为7个层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
DevFrank
2024/07/24
5000
【C++】基础:网络编程介绍与TCP&UDP示例
一文学会 | linux socket编程----TCP
TCP 是基于连接的数据流的协议,先建立连接再进行通信,而且在通信过程中会检查数据是否发送成功。优点就是保证数据的完整性和准确性,缺点就是效率较低。
混说Linux
2022/07/14
3790
一文学会 | linux socket编程----TCP
【网络通信】socket编程——TCP套接字
TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 @TOC
lovevivi
2023/11/17
4260
【网络通信】socket编程——TCP套接字
【Linux】socket网络编程之TCP
创建子进程后子进程关闭监听描述符,再创建一个“孙子”进程,然后子进程退出,此时孙子进程成为孤儿进程,被系统领养,再进行其他的工作,工作完成后关闭描述符,退出时由系统回收 父进程关闭新创建的描述符,然后父进程进入进程等待,这个进程等待的时间很短甚至没有,因为子进程在创建完“孙子”进程后就退出了,父进程就可以回收掉子进程继续下一轮的循环
s-little-monster
2025/05/13
1420
【Linux】socket网络编程之TCP
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
在学习本章之前,先看【Linux网络编程】Socket编程–UDP:实现服务器接收客服端的消息 | DictServer简单的英译汉的网络字典 | 简单聊天室】,里面详细介绍函数的使用方法,小编在这篇文章不再具体介绍。
南桥
2024/11/14
1760
【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行
Socket
Socket模块简单理解就是对socket套接字的封装,当然不是简单的对socket套接字接口的封装,还需要实现一些方法,比如启动非阻塞通信、创建客户端连接、创建服务器连接等。
二肥是只大懒蓝猫
2024/02/07
2240
Socket
C++中的socket编程常用接口
socket() 函数是进行网络编程的基础,它用于创建一个新的套接字(socket)。套接字是网络通信的端点,可以用于在不同计算机之间传输数据。下面是对 socket() 函数的详细解释:
薄荷冰
2024/07/19
2070
Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程
SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程。在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被告知: bind: Address already in use 原因在于服务器重新启动时需要绑定地址: bind (listenfd , (struct sockaddr*)&servaddr, sizeof(servaddr)); 而这个时候网络正处于TIME_WAIT的状态,只有在TIME_WAIT状态退出后,套接字被
Tencent JCoder
2018/07/02
6530
推荐阅读
相关推荐
linux网络编程之socket(三):最简单的回射客户/服务器程序、time_wait 状态
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验