admin 管理员组

文章数量: 887021

Socket(套接字)是计算机网络中的一个抽象层,它允许应用程序通过网络进行通信。套接字用于跨网络的不同主机上的应用程序之间的数据交换。在互联网中,套接字通常基于 TCP(传输控制协议)或 UDP(用户数据报协议)来实现数据的可靠传输或快速传输。

Socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。Socket本质上是一个抽象层 它是一组用于网络通信的API,包括了一系列的函数和数据结构,它提供了一种标准的网络编程接口,使得应用程序可以在网络中进行数据传输。Socket本身并不是一个具体的实现,而是一个抽象的概念。不同的操作系统和编程语言可以通过不同的方式来实现Socket API。

程序也可以用IP+端口号进行唯一标识。那么这个程序的入口就被称作Socket

Socekt编程,我们将TCP协议简化一下,就只有三个核心功能:建立连接、发送数据以及接收数据

  • 用 read() 读取从远程计算机传来的数据;

  • 用 write() 向远程计算机写入数据。

    只要用 socket() 创建了连接,剩下的就是文件操作了。

OSI七层协议

框架内容
应用层HTTP、FTP、Telnet 等等
表示层XDR、ASN.1、SMB、AFP、NCP、等等
会话层ASAP、SSH、RPC、NetBIOS、等等
传输层TCP、UDP、RTP、SCTP 等等
网络层IP、ICMP,IGMP等等
数据链路层以太网,PPP, ATM等等
物理层铜缆、网线、光缆、无线电等等

TCP/IP 协议族

TCP/IP协议中,OSI七层被简化为了四个层次。 TCP/IP模型中的各种协议,依其功能不同,被分别归属到这四层之中,常被视为是简化过后的七层OSI模型。

TCP/IP 中 应用层(应用) 传输层(连接服务) 网络层(网络) 数据链路层(路由器/转运中心) 物理层(网线)

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议

工作人员将手机打包好, 交给了物流(传输层)。接下来手机就到了转运中心(路由器),转运中心根据时间,成本等一系列因素决定下一步该发往哪一个转运中心(网络层)。决定好接下来发往哪一个转运中心后就开始用货车运输了,那么运输的过程就是数据链路层了,链路层负责将数据从一个端点送到另一个端点。那么货车行驶的道路就是物理层。几经周转,手机安全地送到了小明手上。 面向连接指的是先建立连接再发送数据,先去查看从发货地点到小明家中间可不可以进行运输,也就是先确认路可以走得通再发货。如果货物在运输过程中有损坏或者丢失就让京东重新发货,确保小明收到的手机是没有任何问题的。基于字节流的意思就是比如小明买了手机又买了手机配件,分开发货,几件物品不是在一个包裹里,一个一个发。

套接字的使用通常分为服务器端和客户端两部分:

服务器端套接字(Server Socket)

  1. 创建服务器套接字:服务器首先创建一个服务器套接字,指定一个端口号,并等待客户端的连接。

  2. 绑定端口:服务器套接字会绑定到一个特定的端口,以便客户端能够知道如何连接到服务器。

  3. 监听连接:服务器套接字进入监听状态,等待客户端的连接请求。

  4. 接受连接:当客户端尝试连接时,服务器套接字接受连接请求,并创建一个用于与该客户端通信的套接字。

  5. 数据交换:服务器和客户端通过这个新创建的套接字进行数据的读取和写入。

  6. 关闭连接:通信完成后,服务器关闭与客户端的连接,并可以继续监听新的连接请求。

用法

python

import socket
​
# 创建服务器套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
​
# 绑定端口
server_socket.bind(('0.0.0.0', 8080))
​
# 监听连接
server_socket.listen(1)
​
print("服务器正在等待连接...")
​
# 接受连接
client_socket, client_address = server_socket.accept()
print(f"连接来自: {client_address}")
​
# 数据交换
data = client_socket.recv(1024)
print(f"收到数据: {data.decode()}")
​
# 发送数据
client_socket.send(b'Hello, Client!')
​
# 关闭连接
client_socket.close()
server_socket.close()
​

c语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
​
#define PORT 8080
#define BUFFER_SIZE 1024
​
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    
    // 创建套接字文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 绑定套接字到端口
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        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");
        exit(EXIT_FAILURE);
    }
    
    // 监听是否有客户端连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    
    // 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    
    // 读取客户端数据
    read(new_socket, buffer, BUFFER_SIZE);
    printf("客户端消息: %s\n", buffer);
    
    // 向客户端发送数据
    const char *hello = "Hello from server";
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    
    // 关闭套接字
    close(server_fd);
    return 0;
}
​

客户端套接字(Client Socket)

  1. 创建客户端套接字:客户端创建一个套接字,用于与服务器通信。

  2. 指定服务器地址和端口:客户端指定服务器的IP地址和端口号,以便连接到正确的服务器。

  3. 发起连接:客户端尝试与服务器建立连接。

  4. 数据交换:一旦连接建立,客户端可以通过套接字发送请求和接收响应。

  5. 关闭连接:通信完成后,客户端关闭套接字,断开与服务器的连接。

用法

import socket
​
# 创建客户端套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
​
# 连接服务器
client_socket.connect(('localhost', 8080))
​
# 发送数据
client_socket.send(b'Hello, Server!')
​
# 接收数据
data = client_socket.recv(1024)
print(f"收到数据: {data.decode()}")
​
# 关闭连接
client_socket.close()

c语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
​
#define PORT 8080
#define BUFFER_SIZE 1024
​
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    
    // 创建套接字文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 绑定套接字到端口
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        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");
        exit(EXIT_FAILURE);
    }
    
    // 监听是否有客户端连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    
    // 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    
    // 读取客户端数据
    read(new_socket, buffer, BUFFER_SIZE);
    printf("客户端消息: %s\n", buffer);
    
    // 向客户端发送数据
    const char *hello = "Hello from server";
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    
    // 关闭套接字
    close(server_fd);
    return 0;
}
​

Socket(套接字),用大白话来说,就像是你家里的门牌号码和信箱。在网络世界里,电脑或者设备要互相通信,它们也需要一个“门牌号码”来识别谁是谁,以及通过“信箱”来收发信息。

  1. 门牌号码:每个Socket都有一个独一无二的地址,包括IP地址(就像你家的小区、楼号、单元号)和端口号(就像你家的门牌号)。这样,网络数据包就能准确地找到对应的设备和应用程序。

  2. 信箱:Socket本身就像是个信箱,你可以把信息放进信箱里,等待邮递员(操作系统或者网络硬件)来取走并发送出去;同样,邮递员也可以把收到的信件放进信箱里,等待你去取。

  3. 敲门:当你想和另一台电脑的某个程序通信时,你的电脑会通过Socket去“敲门”,也就是发起连接请求。

  4. 聊天:一旦对方回应了你的连接请求,你们就可以开始“聊天”了。这个聊天可以是TCP这样的长对话,也可以是UDP这样的简短交流。

  5. TCP套接字:如果你用TCP Socket,就像是打一个长时间的电话,你们会一直保持通话,直到通话结束。

  6. UDP套接字:如果你用UDP Socket,就像是发邮件或者发短信,你发送信息过去,但对方不一定会立刻回复,甚至可能没有回复。

  7. 监听:服务器上的Socket常常处于“监听”状态,就像门卫一直在注意有没有人来敲门或者信箱里有没有信。

  8. 数据交换:无论是打电话还是发邮件,Socket都负责帮你打包信息,然后发送出去;同时,也帮你从信箱里取出收到的信息。

  9. 结束通信:当你和对方的“聊天”结束后,如果是TCP,你们会正式说“再见”,然后挂断电话;如果是UDP,你们可能就突然停止发送信息了。

  10. 多种用途:Socket可以用于各种网络通信,比如网页浏览、下载文件、视频聊天、在线游戏等等。

总之,Socket就是网络通信中的一个基础工具,它帮助不同的电脑和设备通过互联网找到对方,并且能够互相发送和接收信息。

本文标签: SOCKET