当前位置: 首页 > news >正文

Socket 函数详细讲解(Socket编程步骤、socket函数、TCP和UDP的区别)

Socket 函数详细讲解和 C++ 示例

  • 一、 Socket 基本概念
    • 1. Socket 简介
    • 2. Socket 编程步骤
    • 3. TCP Socket 编程示例
      • 服务器端
      • 客户端
    • 4. 详细说明
  • 二、 socket 函数
    • 1. domain 通讯的协议家族
    • 2. type 数据传输的类型
    • 3. protocol 最终使用的协议
      • 返回值
      • 示例
  • 三、TCP 和 UDP的区别
    • 1. TCP(传输控制协议)
    • 2. UDP(用户数据报协议)
    • 3. 总结
    • 示例应用

一、 Socket 基本概念

1. Socket 简介

Socket 是一种通信机制,允许在不同主机之间或同一主机的不同进程之间进行数据交换。使用 socket 编程可以实现 TCP 和 UDP 协议的网络通信。

2. Socket 编程步骤

  1. 创建 Socket
  2. 绑定(仅服务器)
  3. 监听(仅服务器)
  4. 接受连接(仅服务器)
  5. 连接服务器(仅客户端)
  6. 发送和接收数据
  7. 关闭 Socket

3. TCP Socket 编程示例

服务器端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int server_fd, new_socket;struct sockaddr_in address;int addrlen = sizeof(address);char buffer[BUFFER_SIZE] = {0};// 创建 socket 文件描述符if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 绑定address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);exit(EXIT_FAILURE);}// 监听if (listen(server_fd, 3) < 0) {perror("listen failed");close(server_fd);exit(EXIT_FAILURE);}// 接受连接if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept failed");close(server_fd);exit(EXIT_FAILURE);}// 读取客户端发送的数据read(new_socket, buffer, BUFFER_SIZE);std::cout << "Message from client: " << buffer << std::endl;// 发送数据给客户端const char *message = "Hello from server";send(new_socket, message, strlen(message), 0);std::cout << "Hello message sent\n";// 关闭 socketclose(new_socket);close(server_fd);return 0;
}

客户端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int sock = 0;struct sockaddr_in serv_addr;char buffer[BUFFER_SIZE] = {0};// 创建 socket 文件描述符if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {std::cerr << "Socket creation error" << std::endl;return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// 将地址转换成二进制if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {std::cerr << "Invalid address/ Address not supported" << std::endl;return -1;}// 连接服务器if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {std::cerr << "Connection Failed" << std::endl;return -1;}// 发送数据给服务器const char *message = "Hello from client";send(sock, message, strlen(message), 0);std::cout << "Hello message sent\n";// 读取服务器发送的数据read(sock, buffer, BUFFER_SIZE);std::cout << "Message from server: " << buffer << std::endl;// 关闭 socketclose(sock);return 0;
}

4. 详细说明

  1. 创建 Socket

    • socket(int domain, int type, int protocol)
      • domain: 使用的协议族,例如 AF_INET 表示 IPv4 网络协议。
      • type: Socket 类型,例如 SOCK_STREAM 表示面向连接的 TCP。
      • protocol: 一般设置为 0,让系统自动选择合适的协议。
  2. 绑定

    • bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
      • 将 socket 绑定到特定的 IP 地址和端口号。
  3. 监听

    • listen(int sockfd, int backlog)
      • 使 socket 处于监听状态,准备接受连接。
      • backlog 指定等待连接队列的最大长度。
  4. 接受连接

    • accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
      • 从监听队列中接受一个连接,返回一个新的 socket 文件描述符,用于与客户端通信。
  5. 连接服务器

    • connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
      • 客户端使用这个函数连接到服务器。
  6. 发送和接收数据

    • send(int sockfd, const void *buf, size_t len, int flags)
    • recv(int sockfd, void *buf, size_t len, int flags)
    • readwrite 也可以用于接收和发送数据。
  7. 关闭 Socket

    • close(int sockfd)
      • 关闭 socket 文件描述符。

二、 socket 函数

  • socket(int domain, int type, int protocol)
    • domain: 使用的协议族,例如 AF_INET 表示 IPv4 网络协议。
    • type: Socket 类型,例如 SOCK_STREAM 表示面向连接的 TCP。
    • protocol: 一般设置为 0,让系统自动选择合适的协议。

1. domain 通讯的协议家族

  • PF_INET IPv4互联网协议族。
  • PF_INET6 IPv6互联网协议族。
  • PF_LOCAL 本地通信的协议族。
  • PF_PACKET 内核底层的协议族。
  • PF_IPX IPX Novell协议族。

IPv6尚未普及,其它的不常用。

2. type 数据传输的类型

  • SOCK_STREAM 面向连接的socket:
    -----1)数据不会丢失;2)数据的顺序不会错乱;3)双向通道。
  • SOCK_DGRAM 无连接的socket:
    -----1)数据可能会丢失;2)数据的顺序可能会错乱;3)传输的效率更高。

3. protocol 最终使用的协议

protocol:协议类型

  • 通常为 0,表示自动选择与指定域和类型匹配的协议。
  • 对于 AF_INETSOCK_STREAM,默认为 IPPROTO_TCP
  • 对于 AF_INETSOCK_DGRAM,默认为 IPPROTO_UDP

返回值

  • 成功时返回一个新的套接字描述符。
  • 失败时返回 -1,并设置 errno 以指示错误类型。

示例

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {perror("socket failed");exit(EXIT_FAILURE);
}

在IPv4网络协议家族中,数据传输方式为SOCK_STREAM的协议只有IPPROTO_TCP,数据传输方式为SOCK_DGRAM的协议只有IPPROTO_UDP

本参数也可以为0

socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);    // 创建tcp的sock
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);    // 创建udp的sock

三、TCP 和 UDP的区别

TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议,用于网络通信。它们有各自的优缺点和适用场景。

1. TCP(传输控制协议)

  1. 连接导向

    • TCP是面向连接的协议,在传输数据之前需要建立连接(三次握手)。
    • 连接建立后,双方可以进行可靠的数据传输。
  2. 可靠性

    • 提供可靠的数据传输,确保数据包按顺序到达并且没有丢失或重复。
    • 使用确认机制、重传机制和校验和来保证数据的完整性和正确性。
  3. 流量控制

    • 具有流量控制和拥塞控制机制,防止网络拥塞和发送方发送速度过快。
    • 使用滑动窗口协议来管理流量控制。
  4. 传输速度

    • 由于其可靠性和流量控制机制,TCP的传输速度相对较慢,但可靠性高。
  5. 头部开销

    • TCP头部较大,通常为20字节(不包括可选字段)。
  6. 适用场景

    • 适用于需要高可靠性的数据传输场景,如网页浏览(HTTP/HTTPS)、文件传输(FTP)、电子邮件(SMTP)、远程登录(SSH)等。

2. UDP(用户数据报协议)

  1. 无连接

    • UDP是无连接的协议,在传输数据之前不需要建立连接。
    • 数据包独立发送,无需维护连接状态。
  2. 不可靠性

    • 提供不可靠的数据传输,不保证数据包的顺序、无丢失和无重复。
    • 发送数据后不确认是否到达目的地,不重传丢失的数据包。
  3. 无流量控制

    • UDP没有流量控制和拥塞控制机制,发送速度完全取决于应用程序。
  4. 传输速度

    • 由于没有连接建立、流量控制和重传机制,UDP的传输速度较快,但可靠性低。
  5. 头部开销

    • UDP头部较小,固定为8字节。
  6. 适用场景

    • 适用于对传输速度要求高但对可靠性要求不高的场景,如视频直播、在线游戏、实时语音通话(VoIP)、广播通信等。

3. 总结

特性TCPUDP
连接性面向连接(需要三次握手)无连接
可靠性可靠传输,保证顺序和完整性不可靠传输,不保证顺序和完整性
流量控制有流量控制和拥塞控制无流量控制和拥塞控制
传输速度较慢较快
头部开销较大(20字节,不包括可选字段)较小(8字节)
适用场景需要高可靠性的应用需要高速度的应用

示例应用

  • TCP:HTTP/HTTPS、FTP、SMTP、SSH、Telnet
  • UDP:DNS查询、DHCP、TFTP、在线游戏、视频流、实时音频

了解TCP和UDP的区别及其适用场景,可以帮助开发人员在实际网络编程中选择合适的传输层协议,以满足不同应用的需求。

http://www.lryc.cn/news/353519.html

相关文章:

  • 【限免】杂波环境下线性调频脉冲、巴克码、频率步进脉冲雷达MTI、脉冲压缩【附MATLAB代码】
  • 前端最新面试题(Javascript模块篇)
  • Android11热点启动和关闭
  • DI-engine强化学习入门(三)DI-ZOO强化学习环境搭建与示例运行——Atari
  • 【一站式学会Kotlin】第十节:kotlin 语言的可控性特点和安全调用操作符
  • PaddleClas 指定gpu
  • langchain进阶一:特殊的chain,轻松实现对话,与数据库操作,抽取数据,以及基于本地知识库的问答
  • 【Spring Boot】响应式编程
  • 【C++练级之路】【Lv.21】C++11——列表初始化和声明
  • 输入一串字符串,前中后都有*号,去掉字符串中间和后面的*号,保留前面的*号和字母
  • 【机器学习与大模型】驱动下的应用图像识别与处理
  • 24李林跌落神坛,880还刷吗?还是换1000、900、660?
  • 数据库漫谈-sybase
  • Springboot开发 -- Postman 调试类型详解
  • Windows 后台启动jar并且输出日志到特定日志
  • 垃圾回收机制及算法
  • 蓝桥杯-暴力搜索BFS+DFS
  • 巧用count与count()
  • MongoDB 覆盖索引查询:提升性能的完整指南
  • ECMAScript详解
  • 如何在Windows 10上对硬盘进行碎片整理?这里提供步骤
  • 科学高效备考AMC8和AMC10竞赛,吃透2000-2024年1850道真题和解析
  • SQL——SELECT相关的题目
  • etcd集群部署
  • VBA_MF系列技术资料1-615
  • 常用激活函数学习
  • html中被忽略的简单标签
  • Vue.Draggable:强大的Vue拖放组件技术探索
  • linux mail命令及其历史
  • 数据驱动(Data-Driven)和以数据为中心(Data-Centric)的区别