【Linux后端服务器开发】socket套接字

这篇具有很好参考价值的文章主要介绍了【Linux后端服务器开发】socket套接字。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、socket 套接字概述

二、socket 函数接口

三、IP地址与端口号的网络格式

四、TCP协议的本地通信C语言示例


一、socket 套接字概述

socket 是什么?

socket 本质上是一个抽象的概念,它是一组用于网络通信的 API提供了一种统一的接口,使得应用程序可以通过网络进行通信。在不同的操作系统中,socket 的实现方式可能不同,但它们都遵循相同的规范和协议,可以实现跨平台的网络通信

socket 实现通信的原理是基于网络协议栈
当应用程序创建一个 socket 并指定协议族、类型和使用的协议后,操作系统会创建一个对应的套接字,并把它加入到协议栈中。
协议栈是一个由多个层次协议组成的网络协议体系结构,它负责对数据进行封装和解封装,并确保数据能够在网络上正确传输。

当应用程序通过 socket 发送数据时,操作系统会将数据传递给协议栈的上层协议,该协议会对数据进行封装并添加一些必要的信息,例如目标 IP地址和端口号等。然后将封装后的数据传递给下一层协议,直到数据最终被封装成一个网络包并通过网络发送到目标主机。

当目标主机收到网络包后,协议栈会对数据进行解封装,并将数据传递给操作系统中的套接字。如果该套接字是一个监听套接字,操作系统会创建一个新的套接字来处理连接请求,并将新的套接字加入到协议栈中。如果该套接字是一个已连接套接字,操作系统会将数据传递给应用程序处理。

总之,socket 实现通信的原理是基于网络协议栈,通过将数据封装成网络包并通过网络传输,实现了应用程序之间的通信。操作系统负责管理套接字和协议栈,确保数据能够正确传输。

在Linux中,socket是一种文件类型,伪文件,不占用存储空间,可进行IO操作,可间接看做文件描述符使用。

socket 通信流程图:

【Linux后端服务器开发】socket套接字,Linux后端服务器开发,linux,服务器,网络,socket,TCP,C语言

 

客户端与服务器工作的核心逻辑:

  1. 在客户端向服务器发送请求之前,服务器必须已经初始化完成。
  2. 客户端和服务器的初始化,都需要创建套接字socket,设置IP地址结构体信息。
  3. 服务端在设置完IP地址结构体信息之后,需要bind绑定套接字,通过listen将socket设置为监听状态
  4. 客户端通过connect向服务端发送连接请求,服务端通过accept接收客户端的连接请求,接收成功后获取新的套接字文件描述符。(TCP三次握手)
  5. 客户端发送数据——向文件描述符写入数据write,服务端接收数据——从文件描述符读出数据read,服务端回射数据write,客户端获取回射数据read。
  6. 客户端或服务端发送通信结束信号,close文件描述符,结束通信。(TCP四次挥手)

二、socket 函数接口

socket():创建套接字,返回一个可操作性的文件描述符

int socket(int domain,int type,int protocol);

参数一:表示ip地址类型,常用的有两种

  • 其中AF_INET表示IPv4地址,比如127.0.0.1,这是一个本地 ip
  • 其中AF_INET6表示IPv6地址,比如2001:3CA1:10F:1A:121B:0:0:10

参数二:表示数据传输方式/套接字类型,常见两种

  • SOCK_DGRAM (数据报套接字/无连接的套接字,UDP)
  • SOCK_STREAM(流格式套接字/面向连接的套接字,TCP)

参数三:表示传输协议

  • 理论上前两个参数已经可以推演出采用哪种协议,可以将protocol 的值设为 0,系统自动推演出采用哪种协议

返回值:返回一个套接字(文件描述符fd)

bind():用于服务器,给sockfd套接字绑上本机地址和使用端口,确定了服务器的身份

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数一:套接字的fd(文件描述符),socket()函数的返回值

参数二:结构体 ip+port(端口)

参数三:结构体的字节长度

返回值:判断绑定成功失败

listen():用于服务器,使socket处于监听模式,监听时候有客户端连接,并放入队列(同时设置与服务器建立连接的上限)

int listen(int sockfd, int backlog);

参数一:bind绑定ip和端口的套接字

参数二:请求链接客户端队列的最大存放数目

返回值:判断监听成功失败

accept():用于服务器,接收一个客户端的连接请求,并返回连接客户端的套接字便于IO操作,如果没有客户连接会阻塞等待

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数一:服务器的套接字(也叫监听套接字),表明了自己的身份

参数二:传出参数,跟我建立连接的客户端的结构体(内含客户端ip+端口)

参数三:结构体长度的指针 &sizeof()

返回值:连接客户端的套接字

connect():用于客户端,向远端服务器发送连接请求

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数一:传入参数,客户端对服务器进行IO操作的文件描述符

参数二:绑定需要连接的服务器的结构体(需要初始化绑上ip和端口),表明目的

参数三:结构体的长度

三、IP地址与端口号的网络格式

【Linux后端服务器开发】socket套接字,Linux后端服务器开发,linux,服务器,网络,socket,TCP,C语言

 

IP地址

  • IP一般由32位整数组成,按每8位划分为4部分:255.255.255.255 该显示方式为字符串形式,而IP一般是以整数形式显示。
  • 整数IP地址 unsigned int IP_Addr = 1713350848 转化为二进制为:01100110-00011111-10101000-11000000 根据8位划分得到结果为102-31-168-192,由于网络字节倒序的问题,实际IP为192.168.31.102
  • 在网络通信中,我们输入的是字符串风格的IP地址字符串,这时需要我们将IP地址字符串转换成 uint32_t 的类型进行网络通信,建议直接用库函数 inet_addr(const char* ip) 进行转换。
  • 对于服务器而言,bind绑定套接字的时候,IP地址可用 htonl(INADDR_ANY) 进行任意地址绑定。
// 整数风格 uint32_t 转 字符串风格 ip:
// uint32_t ip;
// struct _ip {
//     unsigned char p1;
//     unsigned char p2;
//     unsigned char p3;
//     unsigned char p4;
// };
// std::string strip = to_string(((struct _ip*)&ip)->p1) + to_string(((struct _ip*)&ip)->p2) +
//                     to_string(((struct _ip*)&ip)->p3) + to_string(((struct _ip*)&ip)->p4);
//
// 字符串风格 转 整数风格:
// 整数风格的ip地址存储方式,占用空间更小,网络通信都使用 uint32_t 的ip格式
// 系统提供的转换方式:inet_addr(const char* ip)
// 任意地址绑定:htonl(INADDR_ANY)

端口号port:

  • 端口号port的数据类型是uint16_t,但是在网络通信中的类型是in_port_t,这其实是uint16_t的重命名,但我们还是需要将port端口号从主机格式转换为网络格式
  • 通过 htons(port) 将端口号信息绑定到 struct sockaddr_in 结构体中。

四、TCP协议的本地通信C语言示例

server.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int main(int args, char* argv[])
{
    if (args != 2)
    {
        printf("Usage:server port\n");
        exit(1);
    }
    uint16_t port = atoi(argv[1]);  // 启动server的时候指定端口号

    // 1. 创建套接字
    int s_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (s_socket < 0)
        exit(1);

    // 2. 绑定套接字
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = htonl(INADDR_ANY);  // Address to accept any incomint message ---> 任意地址绑定
    local.sin_port = htons(port);               // 主机转网络

    if (bind(s_socket, (struct sockaddr*)&local, sizeof(local)) < 0)
        exit(1);
    
    // 3. 监听
    if (listen(s_socket, 5) < 0)
        exit(1);

    // 4. 阻塞等待客户端的连接请求
    struct sockaddr_in peer;
    socklen_t peer_len = sizeof(peer);

    int new_sock = accept(s_socket, (struct sockaddr*)&peer, &peer_len);
    if (new_sock < 0)
        exit(1);

    // 5. 连接成功,面向字节流通信
    while (1)
    {
        char buf[1024];
        int data_len = read(new_sock, buf, sizeof(buf));
        if (data_len == 0)
            break;
        buf[data_len] = 0;
        printf("recv message: %s\n", buf);

        // 6. 发送回射信息(应答数据)
        char out_buf[1024];
        snprintf(out_buf, sizeof(out_buf), "已收到数据: %s\n", buf);
        write(new_sock, out_buf, sizeof(out_buf));
    }

    // 7. 结束连接
    close(s_socket);

    return 0;
}

client.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int args, char* argv[])
{
    if (args != 3)
    {
        printf("Usage: client server_ip server_port\n");
        exit(1);
    }
    char* s_ip = argv[1];
    uint16_t s_port = atoi(argv[2]);

    // 1. 创建套接字
    int c_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (c_socket < 0)
        exit(1);

    // client其实也需要bind绑定,不过这一步不需显式绑定(由OS随机指定)

    // 2. 发送连接请求
    struct sockaddr_in server;
    socklen_t s_len = sizeof(server);
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(s_ip);
    server.sin_port = htons(s_port);

    if (connect(c_socket, (struct sockaddr*)&server, s_len) != 0)
    {
        printf("connect fail\n");
        exit(1);
    }
    
    // 3. 建立连接成功,面向字节流通信
    while (1)
    {
        char buf[1024];
        printf("Enter: ");
        gets(buf);
        write(c_socket, buf, sizeof(buf));

        // 4. 获取服务器的应答数据
        char recv_buf[1024];
        int data_len = read(c_socket, recv_buf, sizeof(recv_buf));
        if (data_len == 0)
            break;
        recv_buf[data_len] = 0;
        printf("%s", recv_buf);
    }

    // 5. 结束通信
    close(c_socket);

    return 0;
}

 

先启动服务器,再启动客户端,运行结果:

【Linux后端服务器开发】socket套接字,Linux后端服务器开发,linux,服务器,网络,socket,TCP,C语言文章来源地址https://www.toymoban.com/news/detail-572763.html

到了这里,关于【Linux后端服务器开发】socket套接字的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux后端服务器开发】UDP协议

    目录 一、端口号 二、UDP报头格式 三、UDP的特点 四、UDP协议实现网络聊天群 端口号port标识了一个主机上进行通信的不同的应用程序。 0 ~ 1023:系统端口号,HTTP、FTP、SSH等这些广为使用的应用层协议,它们的端口号都是固定的系统端口号(知名端口号) 1024 ~ 65535:操作系统

    2024年02月16日
    浏览(40)
  • 【Linux后端服务器开发】IP协议

    目录 一、IP协议概述 二、协议头格式 三、网段划分 四、IP地址的数量限制 五、路由 六、分片和组装 主机 :配有IP地址,但是不进行路由控制的设备 路由器 :即配有IP地址,又能进行路由控制 节点 :主机和路由器的总称 IP :将数据从A主机跨网络传输到B主机的能力,IP =

    2024年02月15日
    浏览(41)
  • 【Linux后端服务器开发】基础IO与文件系统

    目录 一、基础IO 1. C语言文件读写 2. 标志位传参 3. C语言与系统调用关系 二、文件系统 1. 文件描述符 2. 输入输出重定向 文件调用 库函数接口: fopen、fclose、fwrite、fread、fseek 系统调用接口:open、close、write、read、lseek r/w/a :读/写/追加 若打开的文件不存在,“r”报错,“

    2024年02月15日
    浏览(67)
  • 【网络编程】(TCP流套接字编程 ServerSocket API Socket API 手写TCP版本的回显服务器 TCP中的长短连接)

    TCP提供的API主要是两个类:ServerSocket 和 Socket . TCP不需要一个类来表示\\\"TCP数据报\\\"因为TCP不是以数据报为单位进行传输的.是以字节的方式,流式传输 ServerSocket API ServerSocket 是专门给服务器使用的Socket对象. ServerSocket 构造方法: ServerSocket(int port) 创建一个服务端流套接字Socket,并绑

    2024年02月12日
    浏览(62)
  • 【Linux后端服务器开发】封装线程池实现TCP多线程通信

    目录 一、线程池模块 Thread.h LockGuard.h ThreadPool.h 二、任务模块模块 Task.h 三、日志模块 Log.h 四、守护进程模块 Deamon.h  五、TCP通信模块 Server.h Client.h server.cpp client.cpp 关于TCP通信协议的封装,此篇博客有详述: 【Linux后端服务器开发】TCP通信设计_命运on-9的博客-CSDN博客 线程池

    2024年02月16日
    浏览(45)
  • 【Linux后端服务器开发】协议定制(序列化与反序列化)

    目录 一、应用层协议概述 二、序列化与反序列化 Protocal.h头文件 Server.h头文件 Client.h头文件 server.cpp源文件 client.cpp源文件 什么是应用层 ?我们通过编写程序解决一个个实际问题、满足我们日常需求的网络程序,都是应用层程序。 协议是一种“约定”,socket的api接口,在读

    2024年02月16日
    浏览(41)
  • Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

    文章目录: 一:线程池模块分析 threadpool.c 二:UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三:套接字  1.本地套接字 2.本地套 和 网络套对比 server.c client.c threadpool.c   server.c client.c server.c client.c

    2024年02月11日
    浏览(66)
  • 【Linux网络编程】网络编程套接字(TCP服务器)

    作者:爱写代码的刚子 时间:2024.4.4 前言:本篇博客主要介绍TCP及其服务器编码 只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP地址 但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换 字符串转in

    2024年04月14日
    浏览(79)
  • 在Linux系统实现服务器端和客户端的套接字通信

    目录 一.创建一个socket文件夹用来存放编写的服务器端和客户端程序 二.编写服务器端代码 三.编写客户端代码 四.编译c语言程序 五.断开连接 六.可能涉及到的一些没接触过的知识点 (我系统里的文件在temp/socket$文件夹中)   在server.c中编写的代码: 在client中编写的代码:

    2024年02月07日
    浏览(34)
  • 强推Linux高性能服务器编程, 真的是后端开发技术提升, 沉淀自身不容错过的一本经典书籍

    目录 第1章 TCP/IP协议 1.1 TCP/IP协议族体系结构以及主要协议 1.1.1 数据链路层 1.1.2 网络层 1.1.3 传输层 1.1.4 应用层 1.2 封装 1.3 分用 1.5 ARP协议工作原理 1.5.1 以太网ARP请求/应答报文详解 1.5.2 ARP高速缓存的查看和修改 1.5.3 使用tcpdump观察ARP通信过程所得结果如下 本篇核心关键所在

    2024年02月07日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包