Socket通信详解

news2024/11/25 1:09:09

Socket通信详解

文章目录

  • Socket通信详解
    • Socket流程介绍
    • 函数介绍
    • 编程实例

Socket流程介绍

socket通信类似于电话通信,其服务器基本流程就是

Created with Raphaël 2.3.0 安装电话socket() 分配电话号码bind() 连接电话线listen() 拿起话筒accept()

函数介绍

  • socket()

其中socket的函数原型如下所示,它的作用就是创建套接字,同时规定好该套接字的用途

在这里插入图片描述

其中的每个参数的作用如下所示:

domain:套接字使用的协议族信息(比如PF_INET就是使用IVP4互联网协议族)
type:套接字数据传输类型信息(比如SOCK_STREAM是指面向连接的套接字类型,TCP就是这个类型)
protocol:计算机通信中使用的协议信息(比如IPV4,面向连接类型,基本就只有TCP,这里就填写IPPROTO_TCP)
  • bind()

其中bind的函数原型如下所示,它的作用就是把地址信息分配给套接字上,也就是前面socket生成的套接字上。其函数原型如下所示:

在这里插入图片描述

其中中间的__CONST_SOCKADDR_ARG是个宏,继续追踪可以知道是个存储地址信息的结构体,如下所示

在这里插入图片描述

其中每个参数的作用如下所示:

fd:套接字描述符,就是前文socket函数的返回值,结构体信息是绑定在这个套接字上的
addr:存储地址信息的指针,里面有IP和端口信息。
len:就是第二个参数addr的长度

那么addr里面的具体详情又是怎么样的呢,即sockaddr的结构体定义如下所示,是一个14个字节长度的字符串数组。

在这里插入图片描述

为了便于填写,我们一般使用sockaddr_in结构体,然后进行强制类型转换为sockaddr类型,

在这里插入图片描述

上图中的name就是sockaddr_in类型,sockadr_in结构体类型如下所示:

在这里插入图片描述

第一个红框中的变量为sin_family,其演变如下所示

在这里插入图片描述

socket_In结构体的变量解析如下

sin_family:地址族(比如IPV4就填写AF_INET)
sin_port:填写16位网络端口,重点是它是以网络字节序保存,所以需要进行转换
sin_addr:填写32为ip地址,也以网络字节序保存。
sin_zero:无实际含义,为了保持与socket结构体长度一致,方便强制类型转换。
  • listen()

其中listen的函数原型如下所示

在这里插入图片描述

其参数解析如下

fd:前面两个函数都用到过的套接字描述符
n:表示连接请求队列的长度,如果设置为5,则队列长度为5,表示最多使五个连接请求进入队列
  • accept()

其中accept()的函数原型如下所示

在这里插入图片描述

其参数解析如下

fd:服务器的套接字描述符
addr:用来保存发起连接的客户端的地址信息
addr_len:第二个参数的结构体长度,当函数调用完成后,这个参数就是被填入的客户端地址长度
返回值:一个套接字的文件描述符,这个套接字是accept函数生成的用来和这个客户端对话的。

编程实例

  • 文件介绍

    hello_server.c就是主要的文件,也就是实例。hello_client.c是配合服务器测试的客户端程序。Makefile是用来编译两者的。

  • 测试流程

    make
    ./hello_server 9190 //这个端口随便选择一个没有占用的端口即可
    ./hello_client 127.0.0.1 9190//这里的ip和端口号要与服务器的ip端口号保持一致
    

    此时客户端会收到一个消息,消息内容为Message from server: hello World!

  • 测试截图

    服务端运行

在这里插入图片描述

客户端运行以及结果

在这里插入图片描述

  • hello_server.c

    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <unistd.h>
    void error_handling(char* message);
    int main(int argc, char* argv[]) {
      int serv_sock;
      int clnt_sock;
      struct sockaddr_in serv_addr;
      struct sockaddr_in clnt_addr;
      socklen_t clnt_addr_size;
      char message[] = "hello World!";
      if (argc != 2) {
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
      }
      serv_sock = socket(PF_INET, SOCK_STREAM, 0);//创建套接字
      if (serv_sock == -1) {
        error_handling("socket() error");
      }
      memset(&serv_addr, 0, sizeof(serv_addr));
      serv_addr.sin_family = AF_INET;
      serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
      serv_addr.sin_port = htons(atoi(argv[1]));
    
      if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)//将地址信息绑定套接字
        error_handling("bind() error");
      if (listen(serv_sock, 5) == -1) error_handling("listen() error");//监听套接字
      clnt_addr_size = sizeof(clnt_addr);
      clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);//当收到客户端消息的时候创建一个套接字来进行通信
      if (clnt_sock == -1) {
        error_handling("accept() error");
      }
      write(clnt_sock, message, sizeof(message));
      close(clnt_sock);
      close(serv_sock);
      return 0;
    }
    void error_handling(char* message) {
      fputs(message, stderr);
      fputc('\n', stderr);
      exit(1);
    }
    
  • hello_client.c

    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <unistd.h>
    void error_handling(char* message);
    int main(int argc, char* argv[]) {
      int sock;
      struct sockaddr_in serv_addr;
      char message[30];
      int str_len;
      if (argc != 3) {
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
      }
      sock = socket(PF_INET, SOCK_STREAM, 0);
      if (sock == -1) {
        error_handling("socket() error");
      }
      memset(&serv_addr, 0, sizeof(serv_addr));
      serv_addr.sin_family = AF_INET;
      serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
      serv_addr.sin_port = htons(atoi(argv[2]));
    
      if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
        error_handling("connect() error");
      str_len = read(sock, message, sizeof(message) - 1);
      if (str_len == -1) error_handling("read() error");
      printf("Message from server: %s \n", message);
      close(sock);
      return 0;
    }
    void error_handling(char* message) {
      fputs(message, stderr);
      fputc('\n', stderr);
      exit(1);
    }
    
  • MakeFile

    all: server client
    
    server: hello_server.c
    	clang-format -style=google -i hello_server.c
    	gcc hello_server.c -o hello_server
    client: hello_client.c
    	clang-format -style=google -i hello_client.c
    	gcc hello_client.c -o hello_client
    clean:
    	rm hello_client hello_server
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

行测-判断推理-图形推理-样式规律-加减异同

图1图2图3选D图1图2都有的线&#xff0c;则消除图1图2只有一幅图里有的线&#xff0c;则保留选C第一列和第二列都有的线&#xff0c;则消除第一列和第二列只有一幅图里有的线&#xff0c;则保留选A第一列顺时针旋转90&#xff0c;再与第二列去同存异选D第一列和第二列去同存异&…

二叉树、队列、栈、广义表(二)数据结构与算法(十八)

数据结构与算法&#xff08;一&#xff09;-软件设计&#xff08;十七&#xff09;https://blog.csdn.net/ke1ying/article/details/129220378 线性表-队列与栈 队列&#xff1a;先进先出。 栈&#xff1a;先进后出。 循环队列&#xff1a;队投和队尾连接起来。 队空的条件&…

LeetCode 21.剑指 Offer II 078. 合并两个有序链表 | C语言版

LeetCode 21. 合并两个有序链表 | C语言版LeetCode 21. 合并两个有序链表题目描述解题思路思路一&#xff1a;使用栈代码实现运行结果参考文章&#xff1a;思路二&#xff1a;减少遍历节点数代码实现运行结果参考文章&#xff1a;[]()LeetCode 剑指 Offer II 078. 合并排序链表…

《MySQL系列-InnoDB引擎25》表-InnoDB逻辑存储结构

InnoDB逻辑存储结构 从InnoDB存储引擎的逻辑存储结构看&#xff0c;所有数据都被逻辑地存放在一个空间中&#xff0c;称之为表空间(tablespace)。表空间又由段(segment)、区(extent)、页(page)组成。页在一些文档中有时也称为块(block)&#xff0c;InnoDB存储引擎的逻辑存储结构…

JVM系统优化实践(4):以支付系统为例

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e;前面说过&#xff0c;JVM会将堆内存划分为年轻代、老年代两个区域。年轻代会将创建和使用完之后马上就要回收的对象放在里面&#xff0c;而老年代则将创建之后需要…

python刷题

目录标题1、输出前三同学的名字-input().split()2、字典的使用3、DA12 牛客网不同语言使用人数4、DA16 用户常用语言有多少5、python变量1、输出前三同学的名字-input().split() s1 input().split() print(tuple(s1)[:3])2、字典的使用 注意点&#xff1a;1&#xff0c;对字典…

如何使用 FreeSql 无缝接替 EF Core ?

如何使用 FreeSql 无缝接替 EF Core&#xff0c;并实现数据表的 CRUD 操作项目说明DB & 数据表结构DB & 数据表创建数据表 User 实体模型创建使用 EF Core 实现 User 表新增用户信息添加 EF Core 相关的 nuget 包编写 EF Core 操作 User 表的 CRUD 代码FreeSql 使用 Db…

系统启动太慢,调优后我直呼Nice

问题背景最近在负责一个订单系统的业务研发&#xff0c;本来不是件困难的事。但是服务的启动时间很慢&#xff0c;慢的令人发指。单次启动的时间约在10多分钟左右&#xff0c;基本一次迭代、开发&#xff0c;大部分的时间都花在了启动项目上。忍无可忍的我&#xff0c;终于决定…

链路追踪——【Brave】第一遍小结

前言 微服务链路追踪系列博客&#xff0c;后续可能会涉及到Brave、Zipkin、Sleuth内容的梳理。 Brave 何为Brave&#xff1f; github地址&#xff1a;https://github.com/openzipkin/brave Brave是一个分布式追踪埋点库。 #mermaid-svg-riwF9nbu1AldDJ7P {font-family:"…

大数据Hadoop教程-学习笔记05【Apache Hive DML语句与函数使用】

视频教程&#xff1a;哔哩哔哩网站&#xff1a;黑马大数据Hadoop入门视频教程 总时长&#xff1a;14:22:04教程资源: https://pan.baidu.com/s/1WYgyI3KgbzKzFD639lA-_g 提取码: 6666【P001-P017】大数据Hadoop教程-学习笔记01【大数据导论与Linux基础】【17p】【P018-P037】大…

一文带你搞定线程池原理

1.使用线程池的意义何在&#xff1f;项目开发中&#xff0c;为了统一管理线程&#xff0c;并有效精准地进行排错&#xff0c;我们经常要求项目人员统一使用线程池去创建线程。因为我们是在受不了有些人动不动就去创建一个线程&#xff0c;使用的多了以后&#xff0c;一旦报错就…

Android从屏幕刷新到View的绘制(一)之 Window、WindowManager和WindowManagerService之间的关系

0. 相关分享 Android从屏幕刷新到View的绘制&#xff08;一&#xff09;之 Window、WindowManager和WindowManagerService之间的关系 Android从屏幕刷新到View的绘制&#xff08;二&#xff09;之Choreographer、Vsync与屏幕刷新 1. 相关类 WindowManagerService&#xff0c…

Linux安装Redis步骤

1 下载安装包并解压 官网&#xff1a;https://download.redis.io 下载安装包&#xff1a; wget https://download.redis.io/redis-stable.tar.gz 解压 tar -zxvf redis-stable.tar.gz* 2 安装 安装 cd redis-stable make install PREFIX/opt/install/redis6 设置环境变量 vi …

Python学习-----项目设计1.0(设计思维和ATM环境搭建)

目录 前言&#xff1a; 项目开发流程 MVC设计模式 什么是MVC设计模式&#xff1f; ATM项目要求 ATM项目的环境搭建 前言&#xff1a; 我个人学习Python大概也有一个月了&#xff0c;在这一个月中我发布了许多关于Python的文章&#xff0c;建立了一个Python学习起步的专栏…

企业级信息系统开发学习1.3——利用注解配置取代Spring配置文件

文章目录一、利用注解配置类取代Spring配置文件&#xff08;一&#xff09;打开项目&#xff08;二&#xff09;创建新包&#xff08;三&#xff09;拷贝类与接口&#xff08;四&#xff09;创建注解配置类&#xff08;五&#xff09;创建测试类&#xff08;六&#xff09;运行…

史上最经典垃圾回收器(CMS,G1)详解、适用场景及特点、使用命令

文章目录垃圾收集器介绍总结各个垃圾收集器之间的关系垃圾收集器使用命令及默认值详解各个垃圾收集器SerialParNewParallel ScavengeSerial OldParallel OldCMS(Concurrent Mark Sweep)G1(Garbage First)适用场景及推荐垃圾收集器介绍总结 垃圾收集器可以帮助我们进行具体的垃…

HDFS优化

单节点多块磁盘数据均衡 生成HDFS块均衡计划 hdfs diskbalancer -plan node1 执行均衡计划,node1.plan.json均衡计划文件 hdfs diskbalancer -execute node1.plan.json 查看当前均衡任务的执行情况 hdfs diskbalancer -query node1 取消均衡任务hdfs diskbalancer -cancel nod…

(三十九)undo log版本链是个什么东西?

今天我们正式开始切入讲解MySQL中多个事务并发执行时的隔离到底是怎么做的&#xff0c;因为我们知道默认是骚气的RR隔离级别&#xff0c;也就是说脏写、脏读、不可重复读、幻读&#xff0c;都不会发生&#xff0c;每个事务执行的时候&#xff0c;跟别的事务压根儿就没关系&…

移动web基础

初始缩小&#xff1a;布局视口大于视觉视口 初始放大&#xff1a;布局视口小于视觉视口 布局视口等于视觉视口&#xff08;这种动作行为叫做理想视口&#xff09; <meta name"viewport" content"width375" /> <meta name"viewport"…

云原生|kubernetes|网络插件flannel二进制部署和calico的yaml清单部署总结版

前言&#xff1a; 前面写了一些关于calico的文章&#xff0c;但感觉好像是浅尝辄止&#xff0c;分散在了几篇文章内&#xff0c;并且很多地方还是没有说的太清楚云原生|kubernetes|kubernetes的网络插件calico和flannel安装以及切换_calico换flannel_晚风_END的博客-CSDN博客 …