探索Socket编程:从UDP到TCP的全面指南

文章目录

    • [1. 什么是Socket?](#1. 什么是Socket?)
      • [1.1 Socket接口简介](#1.1 Socket接口简介)
    • [2. 基于Socket的TCP通信](#2. 基于Socket的TCP通信)
      • [2.1 TCP通信流程](#2.1 TCP通信流程)
      • [2.2 TCP编程实例](#2.2 TCP编程实例)
    • [3. 基于Socket的UDP通信](#3. 基于Socket的UDP通信)
      • [3.1 UDP通信流程](#3.1 UDP通信流程)
      • [3.2 UDP编程实例](#3.2 UDP编程实例)
    • 总结

在网络编程中, Socket 是一种强大的工具,它在应用层和传输层之间提供了一个抽象层,使得复杂的网络通信变得简单易用。本文将为基础小白介绍 UDP和TCP套接字编程 的基本概念、工作原理及实际应用,帮助大家更好地理解和应用这些技术。

1. 什么是Socket?

Socket 是在应用层和传输层之间的一个抽象层,它将TCP/IP层复杂的操作抽象为几个简单的接口,供应用层调用以实现进程在网络中的通信。Socket起源于UNIX,在Unix的"一切皆文件"哲学下,Socket是一种"打开---读/写---关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接后,可以向自己文件写入内容供对方读取,或读取对方内容,通信结束时关闭文件。

1.1 Socket接口简介

  • socket() :创建Socket
  • bind() :绑定Socket到本地地址和端口,通常由服务端调用
  • listen() :TCP专用,开启监听模式
  • accept() :TCP专用,服务器等待客户端连接,一般是阻塞态
  • connect() :TCP专用,客户端主动连接服务器
  • send() :TCP专用,发送数据
  • recv() :TCP专用,接收数据
  • sendto() :UDP专用,发送数据到指定的IP地址和端口
  • recvfrom() :UDP专用,接收数据,返回数据远端的IP地址和端口
  • close() :关闭Socket

2. 基于Socket的TCP通信

TCP(传输控制协议) 是一种面向连接的可靠传输协议,在数据传输之前需要建立连接,这个过程通常称为三次握手。TCP保证数据传输的可靠性,因此适用于需要高可靠性的场景。

2.1 TCP通信流程

服务端(被动连接,需要创建自己的地址信息):

  1. 创建一个套接字socket()
  2. 绑定IP地址、端口等信息到Socket上bind()
  3. 监听套接字listen()
  4. 等待客户端的连接请求accept()
  5. 发送、接收数据send()recv(),或者read()write()
  6. 关闭网络连接close()

客户端

  1. 创建一个套接字socket()
  2. 连接服务器connect()
  3. 接收、发送数据send()recv(),或者read()write()
  4. 关闭网络连接close()

2.2 TCP编程实例

服务端(service.c)

c 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main() {
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(1258);
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    listen(serv_sock, 20);
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);
    int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
    char str[] = "Hello World!";
    write(clnt_sock, str, sizeof(str));
    close(clnt_sock);
    close(serv_sock);
    return 0;
}

客户端(client.c)

c 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(1258);
    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    char buffer[40];
    read(sock, buffer, sizeof(buffer) - 1);
    printf("Message from server: %s\n", buffer);
    close(sock);
    return 0;
}

利用python具体案例请点击------->》python课程设计作业-TCP客户端-服务端通信-CSDN博客

3. 基于Socket的UDP通信

UDP(用户数据报协议) 是一种无连接的传输协议,数据传输时不需要建立连接,直接发送数据到目标地址即可。UDP适用于实时性要求高的数据传输场景,例如视频直播、在线游戏等。

3.1 UDP通信流程

服务端

  1. 建立套接字文件描述符socket()
  2. 设置服务器IP地址和端口,初始化要绑定的网络地址结构
  3. 绑定IP地址、端口等信息bind()
  4. 循环接收客户端的数据recvfrom()
  5. 向客户端发送数据sendto()
  6. 关闭套接字close()

客户端

  1. 建立套接字文件描述符socket()
  2. 设置服务器IP地址和端口struct sockaddr
  3. 向服务器发送数据sendto()
  4. 接收服务器的数据recvfrom()
  5. 关闭套接字close()

3.2 UDP编程实例

服务端(service.c)

c 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#define SERV_PORT 3000

int main() {
    int sock_fd;
    int recv_num;
    int send_num;
    int client_len;
    char recv_buf[20];
    struct sockaddr_in addr_serv;
    struct sockaddr_in addr_client;
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_fd < 0) {
        perror("socket");
        exit(1);
    } else {
        printf("sock successful\n");
    }
    memset(&addr_serv, 0, sizeof(struct sockaddr_in));
    addr_serv.sin_family = AF_INET;
    addr_serv.sin_port = htons(SERV_PORT);
    addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
  
    client_len = sizeof(struct sockaddr_in);
    if (bind(sock_fd, (struct sockaddr *)&addr_serv, sizeof(struct sockaddr_in)) < 0) {
        perror("bind");
        exit(1);
    } else {
        printf("bind successful\n");
    }
    while (1) {
        printf("begin recv:\n");
        recv_num = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&addr_client, &client_len);
        if (recv_num < 0) {
            printf("bad\n");
            perror("recvfrom");
            exit(1);
        } else {
            recv_buf[recv_num] = '\0';
            printf("recv successful:%s\n", recv_buf);
        }
        printf("begin send:\n");
        send_num = sendto(sock_fd, recv_buf, recv_num, 0, (struct sockaddr *)&addr_client, client_len);
        if (send_num < 0) {
            perror("sendto");
            exit(1);
        } else {
            printf("send successful\n");
        }
    }
    close(sock_fd);
    return 0;
}

客户端(client.c)

c 复制代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define DEST_PORT 3000
#define DEST_IP_ADDRESS "192.168.1.103"

int main() {
    int sock_fd;
    int send_num;
    int recv_num;
    int dest_len;
    char send_buf[20] = {"hello tiger"};
    char recv_buf[20];
    struct sockaddr_in addr_serv;
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&addr_serv, 0, sizeof(addr_serv));
    addr_serv.sin_family = AF_INET;
    addr_serv.sin_addr.s_addr = inet_addr(DEST_IP_ADDRESS);
    addr_serv.sin_port = htons(DEST_PORT);
  
    dest_len = sizeof(struct sockaddr_in);
    printf("begin send:\n");
    send_num = sendto(sock_fd, send_buf, sizeof(send_buf), 0, (struct sockaddr *)&addr_serv, dest_len);
    if (send_num < 0) {
        perror("sendto");
        exit(1);
    } else {
        printf("send successful:%s\n", send_buf);
    }
    recv_num = recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&addr_serv, &dest_len);
    if (recv_num < 0) {
        perror("recvfrom");
        exit(1);
    } else {
        printf("recv successful\n");
    }
    recv_buf[recv_num] = '\0';
    printf("the receive:%s\n", recv_buf);
    close(sock_fd);
    return 0;
}

总结

通过本文的介绍,我们学习了Socket编程 的基本概念和应用,包括TCPUDP 两种网络通信协议的编程方法。Socket作为网络编程的基础工具,使得复杂的网络通信变得更加简洁易用。希望通过本文的学习,大家能够更好地理解和应用Socket编程,为进一步的网络编程打下坚实的基础。

相关推荐
千天夜1 小时前
使用UDP协议传输视频流!(分片、缓存)
python·网络协议·udp·视频流
长弓三石2 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
xianwu5432 小时前
反向代理模块
linux·开发语言·网络·git
follycat2 小时前
[极客大挑战 2019]HTTP 1
网络·网络协议·http·网络安全
xiaoxiongip6663 小时前
HTTP 和 HTTPS
网络·爬虫·网络协议·tcp/ip·http·https·ip
JaneJiazhao3 小时前
HTTPSOK:智能SSL证书管理的新选择
网络·网络协议·ssl
CXDNW3 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
无所谓จุ๊บ4 小时前
树莓派开发相关知识十 -小试服务器
服务器·网络·树莓派
道法自然04024 小时前
Ethernet 系列(8)-- 基础学习::ARP
网络·学习·智能路由器
EasyCVR5 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频