c++ socket网络编程详解

一、c socket 异步接收

c socket支持两种类型的接收模式:阻塞模式和非阻塞模式,但是在大量的数据传输时,阻塞模式一定会造成数据的丢失和延迟,所以使用异步接收通常是一个更加可靠的解决办法。在c++ socket中,我们可以使用select函数来实现异步接收。

while(1) {
    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(sock_fd, &read_fds);
    if(select(sock_fd+1, &read_fds, NULL, NULL, NULL) <= 0) {
         continue;
    }
    if(FD_ISSET(sock_fd, &read_fds)) {
         recv(sock_fd, buffer, size, 0);
    }
}

在上述代码中,我们使用select函数监听我们的socket,当有数据可读时,便会进入recv函数来接收数据。

二、c socket 长连接

在网络编程中,短连接是指每次请求都需要建立一个新的连接,而长连接则是可以一直保持连接状态,在后续请求中都可以复用这个连接。

在c++ socket中,通过设置socket的选项SO_KEEPALIVE为1(开启TCP心跳包机制)和TCP_NODELAY为1(禁用Nagle算法),我们可以实现长连接的功能。

int optval = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));

三、c socket技术

c++ socket编程中需要使用到的技术包括:TCP/IP协议、Socket编程、多线程、select的应用、数据加密和压缩等。以下是一个基本的c++ socket示例代码,实现了TCP连接和发送一条消息的功能。

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[]) {

    int sock_fd;
    struct sockaddr_in server_addr;
    char msg[] = "Hello, world!";

    // create socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_fd == -1) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // set server address
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // connect to server
    if(connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("connect failed");
        exit(EXIT_FAILURE);
    }

    // send message
    if(send(sock_fd, msg, strlen(msg), 0) < 0) {
        perror("send failed");
        exit(EXIT_FAILURE);
    }

    // close socket
    close(sock_fd);
    return 0;
}

四、c socket通讯源代码

以下是一个基于select函数实现的简单通信源代码,包括服务器端和客户端。

服务器端

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[]) {

    int listen_fd, max_fd, client_fd[FD_SETSIZE], conn_fd;
    int nready;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len;
    char buffer[256];
    fd_set read_set, all_set;
    int i;

    // create listen socket
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(listen_fd == -1) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // set server address
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);

    // bind listen_fd
    if(bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // listen to client requests
    if(listen(listen_fd, 10) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    max_fd = listen_fd;
    for(i = 0; i < FD_SETSIZE; i++)
        client_fd[i] = -1;

    FD_ZERO(&all_set);
    FD_SET(listen_fd, &all_set);

    printf("Server running...\n");

    while(1) {
        read_set = all_set;
        nready = select(max_fd+1, &read_set, NULL, NULL, NULL);
        if(nready < 0) {
            perror("select failed");
            exit(EXIT_FAILURE);
        }

        // if new client request
        if(FD_ISSET(listen_fd, &read_set)) {
            client_len = sizeof(client_addr);
            conn_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
            if(conn_fd < 0) {
                perror("accept failed");
                continue;
            }

            for(i = 0; i < FD_SETSIZE; i++) {
                if(client_fd[i]  max_fd) {
                max_fd = conn_fd;
            }
        }

        for(i = 0; i < FD_SETSIZE; i++) {
            if(client_fd[i] < 0)
                continue;
            if(FD_ISSET(client_fd[i], &read_set)) {
                memset(buffer, 0, sizeof(buffer));
                if(read(client_fd[i], buffer, sizeof(buffer)-1) == 0) {
                    printf("client[%d] closed\n", i);
                    close(client_fd[i]);
                    FD_CLR(client_fd[i], &all_set);
                    client_fd[i] = -1;
                } else {
                    printf("recv from client[%d]: %s\n", i, buffer);
                }
            }
        }
    }

    // close listen_fd
    close(listen_fd);
    return 0;
}

客户端

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[]) {

    int sock_fd;
    struct sockaddr_in server_addr;
    char buffer[256];

    // create socket
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_fd == -1) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // set server address
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // connect to server
    if(connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("connect failed");
        exit(EXIT_FAILURE);
    }

    // send message
    strcpy(buffer, "Hello, world!");
    send(sock_fd, buffer, strlen(buffer), 0);
    printf("send message: %s\n", buffer);

    // close socket
    close(sock_fd);
    return 0;
}

五、c socket设置阻塞

在c++ socket编程中,我们默认使用阻塞模式来进行通信,即当进行读写操作时,程序将一直等待,直到I/O操作完成或者到达超时时间。

阻塞模式可以通过设置socket的O_NONBLOCK选项来实现非阻塞模式:

int flags = fcntl(sock_fd, F_GETFL, 0);
fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK);

六、c socket传输

c++ socket中传输数据通常是通过send和recv函数进行。以下是一个基本的发送和接收数据的示例代码:

发送数据

char buffer[256];
strcpy(buffer, "Hello, world!");
send(sock_fd, buffer, strlen(buffer), 0);

接收数据

char buffer[256];
memset(buffer, 0, sizeof(buffer));
recv(sock_fd, buffer, sizeof(buffer)-1, 0);
printf("recv message: %s\n", buffer);

七、c socket编程基础

c++ socket编程的基础可以分为以下几个方面:

1. c socket 构造

c++ socket的构造需要使用socket函数,该函数包括三个参数:地址族、套接字类型和协议。

int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

2. c socket函数

c++ socket编程需要使用一些关键的函数,包括bind、listen、accept、connect、send和recv等。以下是这些函数的基本使用方法:

bind函数

将socket与地址绑定:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen函数

告诉socket开始监听连接请求:

listen(sock_fd, 10);
accept函数

接受客户端的连接请求:

struct sockaddr_in client_addr;
int client_fd = accept(sock_fd, (struct sockaddr*)&client_addr, &client_len);
connect函数

向服务器发起连接请求:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
send函数

发送数据到对端:

char buffer[256];
strcpy(buffer, "Hello, world!");
send(sock_fd, buffer, strlen(buffer), 0);
recv函数

从对端接收数据:

char buffer[256];
memset(buffer, 0, sizeof(buffer));
recv(sock_fd, buffer, sizeof(buffer)-1, 0);
printf("recv message: %s\n", buffer);

3. c语言socket通信

在c++ socket编程中,使用的通信协议通常是TCP/IP。

TCP/IP协议采用了面向连接的方式进行通信,可以保证数据的可靠性和完整性。但是,相比于UDP协议,TCP/IP协议的速度会稍微慢一些。

c++ socket编程中应用广泛的通信方式有:单客户端单线程、单客户端多线程、多客户端单线程和多客户端多线程。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/271379.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝的头像小蓝
上一篇 2024-12-16 14:55
下一篇 2024-12-16 14:55

相关推荐

  • Python中使用socket传输图片

    本文将从多个方面介绍如何使用Python中的socket模块传输图片,涉及到准备工作、发送方部分和接收方部分的详细代码实现。 一、准备工作 在使用Python中的socket模块进…

    编程 2025-04-28
  • Python Socket阻塞问题的解析

    本文将从多个方面对Python socket阻塞问题进行详细阐述,包括阻塞的原因、影响、解决方法等等。 一、阻塞的原因 阻塞是指在等待某个事件的过程中,该进程无法处理其他任务,直到…

    编程 2025-04-27
  • C# Socket关闭后客户端仍可连接的解决方法

    对于C# Socket通信中的一些问题,多数人可能已经熟知,但是有些问题仍然困扰着一部分人,例如Socket关闭后,客户端仍然可以连接。本篇文章将在此问题为中心,围绕该问题的原因和…

    编程 2025-04-27
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25

发表回复

登录后才能评论