彻底弄懂套接字

article/2025/10/20 21:10:20

1.什么是套接字(英文名:插座)

        套接字(socket)是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。Linux所提供的功能(如打印服务、连接数据库和提供Web页面)和网络工具(如用于远程登录的rlogin和用于文件传输的ftp)通常都是通过套接字来进行通信的。

        套接字的创建和使用与管道是有区别的,因为套接字明确地将客户和服务器区分开来。套接字机制可以实现将多个客户连接到一个服务器。

2.套接字的域

      指定套接字通信中使用的网络介质。最常见的套接字域是AF_INET,它指的是Internet网络,许多Linux局域网使用的都是该网络,当然,因特网自身用的也是它。其底层的协议——网际协议(IP)只有一个地址族,它使用一种特定的方式来指定网络中的计算机,即人们常说的IP地址。

3.套接字类型

        一个套接字域可能有多种不同的通信方式,而每种通信方式又有其不同的特性。但AF_UNIX域的套接字没有这样的问题,它们提供了一个可靠的双向通信路径。在网络域中,我们就需要注意底层网络的特性,以及不同的两种通信机制:流(stream)数据报(datagram)。它们有着截然不同的服务层次。

 (1)流套接字

                流套接字(在某些方面类似于标准的输入/输出流)提供的是一个有序、可靠、双向字节流的连接。因此,发送的数据可以确保不会丢失、复制或乱序到达,并且在这一过程中发生的错误也不会显示出来。大的消息将被分片、传输、再重组。这很像一个文件流,它接收大量的数据,因为它们在编写网络程序时是最常用的。

                TCP/IP代表的是传输控制协议/网际协议。IP协议是针对数据包的底层协议,它提供从一台计算机通过网络到达另一台计算机的路由。TCP协议提供排序,流控和重传,以确保大数据的传输可以完整地到达目的地或报告一个适当的错误条件。

(2)数据报套接字

                与流套接字相反,由类型SOCK_DGRAM指定的数据报套接字不建立和维持一个连接。它对可以发送的数据报的长度有限制。数据报作为一个单独的网络消息被传输,它可能会丢失、复制或乱序到达。

                数据报套接字是在AF_INET域中通过UDP/IP连接实现的,它提供的是一种无序的不可靠服务(UDP代表的是用户数据报协议)。但从资源的角度来看,相对来说它们开销比较小,因为不需要维持网络连接。而且因为无需花费时间来建立连接,所以它们的速度也很快。

                数据报适用于信息服务中“单次”(singl-shot)查询,它主要用来提供日常状态信息或执行低优先级的日志记录。它的优点是服务器的崩溃不会给客户造成不便,也不会要求客户重启,因为基于数据报的服务器通常不保留连接信息,所以它们可以在不打扰其客户的前提下停止并重启。

4.套接字协议

        只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。那么这里提供了UNIX网络套接字文件系统套接字,它们不需要你选择一个特定的协议,只需要使用其默认值即可。(这里将不详细讨论这两种)

5.创建套接字

        socket系统调用创建一个套接字并返回一个描述符,该描述符可以用来访问该套接字。

#include <sys/types.h>
#include <sys/socket.h>int socket(int domain,int protocol);

        创建的套接字是一条通信线路的一个端点,domain参数指定协议族,type参数指定这个套接字的通信类型,protocol参数指定使用的协议。             

        domain参数可以指定的协议族如下图:

  

        最常见的套接字域是AF_UNIX和AF_INET,前者用于通过UNIX和Linux文件系统实现的本地套接字,后者用于UNIX网络套接字。AF_INET套接字可以用于通过包括因特网在内的TCP/IP网络进行通信的程序。微软Windowns系统的Windowns接口也提供了对这个套接字域的访问功能。

        socket函数的参数type指定用于新套接字的通信特性。它的取值包括SOCK_STREAM和SOCK_DGRAM。

        SOCK_STREAM是一个有序、可靠、面向连接 的双向字节流,对AF_INET域套接字来说,它默认是通过一个TCP连接来提供这一特性的,TCP连接在两个流套接字端点之间建立。数据可以通过套接字连接进行双向传递。TCP协议所提供的机制可以用于分片和重组长消息,并且可以重传可能在网络中丢失的数据。        

        socket系统调用返回一个描述符,它在许多方面都类似于底层的文件描述符。当这个套接字连接到另一端的套接字后,我们就可以用read和write系统调用,通过这个描述符来在套接字上发送和接收数据了。close系统调用用于结束套接字连接。

6.套接字地址

        每个套接字域都有其自己的地址格式。对于AF_UNIX域套接字来说,它的地址由结构sockaddr_un来描述,该结构定义在头文件sys/un.h中。

struct sockaddr_un{sa_family_t    sun_family;    /* AF_UNIX */char           sun_path[];    /* pathname */
};

        因此,对套接字进行处理的系统调用可能需要接受不同类型的地址,每种地址格式都使用一种类似的结构来描述,它们都以一个指定地址类型(套接字域)的成员(在本例中是sun_family)开始。在AF_UNIX域中,套接字地址由结构中的sun_path成员中的文件名所指定。

        在当前的Linux系统中,由X/Open规范定义的类型sa_family_t在头文件sys/un.h中声明,它是短整型。此外,sun_path指定的路径名长度也是有限制的(Linux规定的是108个字符,其他系统可能使用的是更清楚的常量,如UNIX_MAX_PATH)。因为地址结构的长度不一致,所以许多套接字调用需要用到一个用来复制特定地址结构的长度变量或将它作为一个输出。

        在AF_INET域中,套接字地址由结构sockaddr_in来指定,该结构定义在头文件netinet/in.h中,它至少包含以下几个成员:

struct sockaddr_in{short int                sin_family;        /* AF_INEX */unsigned short int       sin_port;          /* Port number */struct in_addr           sin_addr;          /* Internet address */      
};

 IP地址结构in_addr被定义为:

struct  in_addr{unsigned  long  int      s_addr;
};

 IP地址中的4个字节组成一个32位的值。一个AF_INET套接字由它的域、IP地址和端口号来完全确定。从应用程序的角度来看,所有套接字的行为就像文件描述符一样,并且通过一个唯一的整数值来区分。

7.命名套接字

        要想让通过sockket调用创建的套接字可以被其他进程使用,服务器程序就必须给该套接字命名。这样,AF_UNIX套接字就会关联到一个文件系统的命名。

#include <sys/socket.h>int bind(int socket, const struct sockaddr *address, size_t address_len);

         bind系统调用把参数address中的地址分配给文件描述符socket关联的未命名套接字。地址结构的长度由参数address_len传递。

        地址的长度和格式取决于地址族。bind调用需要将一个特定的地址结构指针转换为指向通用地址类型(struct sockaddr *)。

        bind调用在成功时返回0,失败时返回-1并设置errno为下表中的一个值。

AF_UNIX域套接字还有其他一些错误代码,如下表。 

 8.创建套接字队列

        为了能够在套接字上接受进入的连接,服务器程序必须创建一个队列来保存未处理的请求。它用listen系统调用来完成这一工作。

#include <sys/socket.h>int listen(int socket, int backlog);

         Linux系统可能会对队列中可以容纳的未处理连接的最大数目做出限制。为了遵守这个最大值限制,listen函数将队列长度设置为backlog参数的值。在套接字队列中,等待处理的进入连接的个数最多不能超过这个数字。再往后的连接将被拒绝,导致客户的连接请求失败。listen函数提供的这种机制允许当服务器程序正忙处理前一个客户请求的时候,将后续的客户连接放入队列等待处理。backlog参数常用的值为5.

        listen函数在成功时返回0,失败时返回-1.错误代码包括EBADF、EINVAL和ENOTSOCK,其含义与上面bind系统调用中说明的一样。

9.接受连接

        一旦服务器程序创建并命名了套接字之后,它就可以通过accept系统调用来等待客户建立对该套接字的连接。

#include <sys/socket.h>int accept(int socket, struct sockaddr *address, size_t *address_len);

         accept系统调用只有当有客户程序试图连接到由socket参数指定的套接字上时才返回。这里的客户是值在套接字队列中排第一个的未处理连接。accept函数将创建一个新套接字来与该客户进行通信,并且返回新套接字的描述符。新套接字的类型和服务器监听套接字类型一样的。

        套接字必须事先由bind调用命名,并且由listen调用给它分配一个连接队列。连接客户的地址将被放入address参数指向的sockaddr结构中。如果我们不关心客户的地址,也可以将address参数指定为空指针。

        参数addr_len指定客户结构的长度。如果客户地址的长度超过这个值,它将被截断。所以在调用accept之前,address_len必须被设置为预期的地址长度。当这个调用返回时,address_len将被设置为连接客户地址结构的实际长度。

        如果套接字队列中没有未处理的连接,accept将阻塞(程序将1暂停)直到有客户建立连接为止。我们可以通过对套接字文件描述符设置O_NONBLOCK标志来改变这一行为,使用的函数是fcnt1,如下:

int flags = fcnt1(socket, F_GETFL, 0);fcnt1(socket, F_SETFL, O_NONBLOCK|flags);

         当有未处理的客户连接时,accept函数将返回一个新的套接字文件描述符。发生错误时,accept函数将返回-1,可能的错误情况大部分与bind、listen调用类似,其他的错误有EWOULDBLOCK和EINTR。前者是当指定了O_NONBLOCK标志,但队列中没有未处理连接时产生的错误。后者是当进程阻塞在accept调用时,执行被中断而产生的错误。

10.请求连接

        客户程序通过在一个未命名套接字和服务器监听套接字之间建立连接的方法来连接到服务器。它们通过connect调用来完成这一工作。

#include <sys/socket.h>int connect(int socket, const struct sockaddr *address, size_t address_len);

         参数socket指定的套接字将连接到参数address指定的服务器套接字,address指向的结构的长度由参数address_len指定。参数socket指定的套接字必须是通过socket调用获得的一个有效的文件描述符。

        成功时,connect调用返回0,失败时返回-1.可能的错误代码见下表。

         如果连接不能立刻建立,connect调用将阻塞一段不确定的超时时间。一旦这个超时时间到达,连接将被放弃,connect调用失败。但如果connect调用被一个信号中断,而该信号又得到了处理,connect调用还是会失败(errno被设置为EINTR),但连接尝试并不会被放弃,而是以异步方式继续建立,程序必须在此后进行检查以查看连接是否成功建立。

        与accept调用一样,connect调用的阻塞特性可以通过设置该文件描述符的O_NONBLOCK标志来改变。此时,如果连接不能立刻建立,connect将失败并把errno设置为EINPROGRESS,而连接将以异步方式继续进行。

        虽然异步连接难于处理,但我们可以在套接字文件描述符上用select调用来检查套接字是否已处于就绪状态。(此处先不将select调用)

11.关闭套接字

        你可以通过调用close函数来终止服务器和客户上的套接字连接,就如同对底层文件描述符进行关闭一样。你应该总是在连接的两端都关闭套接字。对于服务器来说,应该在read调用返回0时关闭套接字,但如果套接字是一个面向连接类型的,并且设置了SOCK_LINGER选项,close调用会在改套接字还有未传输数据时阻塞。(这里就涉及到如何设置套接字选项,这里不细讲)

 

 


http://chatgpt.dhexx.cn/article/uik4d78l.shtml

相关文章

什么是套接字?Socket基本介绍

什么是套接字&#xff1f;Socket基本介绍 一、什么是套接字&#xff1f;二、套接字特性三、套接字缓冲区 一、什么是套接字&#xff1f; 套接字是一种通信机制&#xff08;通信的两方的一种约定&#xff09;&#xff0c;socket屏蔽了各个协议的通信细节&#xff0c;提供了tcp/…

微信小程序-引入地图、获得经纬度

实际这是一个获得经纬度的方法&#xff0c;但是有了经纬度可以做很多事情 点击按钮跳转到一个单独的页面&#xff08;地图&#xff0c;可导航&#xff09;在页面内嵌一个独立的小区域 首先可看一下腾讯地图官方文档 微信小程序JavaScript SDK | 腾讯位置服务 最基本&#xf…

微信小程序-批量地图标记

效果图 wxml <loading hidden"{{!loading}}">加载中</loading><view class"mapBox"><map id"myMap" scale"12" longitude"{{longitude}}" latitude"{{latitude}}" markers"{{mark…

实现地图功能 利用微信内置的微信地图

效果图&#xff1a; 查看微信开发文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/api/location/wx.chooseLocation.html 其实不难&#xff0c;查看官方文档&#xff0c;一目了然 直接上代码&#xff1a; map.wxml: <button bindtap"mapViewTap&…

微信小程序应用百度地图API

微信小程序&#xff0c;定位地点&#xff0c;应用bdmap API 1 申请 百度地图开放平台页面&#xff1a;控制台&#xff0c;添加应用 应用类型选微信小程序&#xff0c;添加微信小程序名称和APP ID 2. 微信小程序后台设置 进入微信公众平台&#xff0c;开发管理 服务器域名&a…

微信接入js-sdk-获取地理位置,打开微信内置地图

1.第一步当然是已经正确接入了微信并且配置好了回调安全域名。不会的朋友可以看看《微信开发-初级接入微信公众平台MP》 2. 引用微信js-sdk, http://res.wx.qq.com/open/js/jweixin-1.0.0.js&#xff0c;然后通过config接口注入权限验证配置。先在自己的服务器上写个获取数据…

微信地图 leaflet 腾讯地图

本来在微信项目中使用的高德地图&#xff0c;发现不是想象中的好用&#xff0c;而且用了微信&#xff0c;感觉使用腾讯地图会比较方便&#xff0c;所以&#xff0c;索性使用leaflet腾讯地图的底图来实现。 其中关于正确使用腾讯地图参考了https://github.com/wuxiashuangji/TX…

微信地图组件小程序报错“permission“

报错原因 地图可以任意添加&#xff0c;但用户的位置属于个人隐私&#xff0c;因此需要添加服务引导程序&#xff0c;告知用户地理位置的获取。需要添加 Permission &#xff08;小程序权限获取设置&#xff09;。 解决方法 该片段用于获取位置权限&#xff0c;注意该片段如…

uniapp 微信对接地图的三种操作

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 1.uni.getLocation 获取当前经维度 先上代码 let that this// 获取用户是否开启 授权获取当前的地理位置、速度的权限。uni.getSetting({success (res) {console.log(res)// 如果没有授权if (!res.au…

微信地图多边形算法及判断点位是否在多边形中

最新一个小项目,需要用到地图定义自由区域,并判断选点是否落在此区域内,思路是通过map的polygons中的points来定义多边形边界,通过polygons的fillColor 、 strokeColor、strokeWidth来进行选区颜色的渲染。 然后再通过地图中心点位的移动来确定需要判断的选点(因为小程序地…

【微信小程序】打开微信内置的地图

前言 略 打开微信内置的地图 wx.openLocation({latitude: 38.043622, /*纬度&#xff0c;使用 gcj02 国测局坐标系*/longitude: 114.514746, /*经度&#xff0c;使用 gcj02 国测局坐标系*/scale: 18, /*缩放比例&#xff0c;范围5~18*/name: 石家庄市长安公园人民广场, /*这…

小程序 – 调用微信地图功能小记 + 滑动事件

学习文献官方API对 location 地图 API的具体分析日历插件 - github 2-有回调事件小程序滚动问题小程序上下滑动事件小程序map地图上显示多个marker wx.getLocation(Object object) -获取当前的地理位置、速度。并且能打印出地址消息&#xff1b; wx.openLocation() – 是使用…

微信地图wgs84坐标,gcj02坐标,bd09坐标转换

微信小程序三种常见经纬度坐标系的转化 遇见问题&#xff1a;在其它端点位显示正常&#xff0c;在小程序上点位发生偏移&#xff0c;微信小程序是gcj02坐标&#xff0c;就是xxToGcj02&#xff0c;具体情况具体分析 我们常用的地图api坐标系有wgs84坐标系&#xff0c;gcj02坐标…

Android仿微信地图定位和位置选择(上)

一、地图集成 集成腾讯地图SDK&#xff0c;https://lbs.qq.com/&#xff0c;申请AppKey。 1、dependencies implementation com.tencent.map.geolocation:TencentLocationSdk-openplatform:7.2.6 implementation com.tencent.map:tencent-map-vector-sdk:4.3.4 2、AndroidMa…

微信公众号h5界面获取展示微信内置地图与地图坐标间的转换 — 微信地图(gcj02)转为百度地图

此文章中实例用测试号进行演示 。getLocation openLocation 主要运用微信JS-SDK&#xff0c;微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。通过使用微信JS-SDK&#xff0c;网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能…

微信小程序地图功能

一&#xff0c;显示地图 <map id"map" longitude"{{longitude}}" latitude"{{latitude}}" scale"14" controls"{{controls}}" bindcontroltap"controltap" markers"{{markers}}" bindmarkertap"…

微信小程序---高德地图API

本文章介绍微信小程序调用高德地图API的过程&#xff0c;使用高德定位功能做演示。微信小程序目前支持百度地图、高德地图、腾讯地图。用法可以说是基本完全一样&#xff0c;本文章以高德为例&#xff0c;简单说一下他们的区别&#xff0c;高德地图精度应该是最准确的&#xff…

微信小程序地图控件Map的使用

本文介绍微信小程序map控件的使用 map为原生控件之一…… 介绍完map控件之后下面直接来看代码怎么实现吧 和往常一样&#xff0c;这些代码贴过去就可以直接通用的 首先wxml文件(极简)&#xff1a; <map id"map" scale"16" controls"{{controls}}&…

微信小程序地图导航实例讲解

微信小程序地图导航实例讲解 先上演示视频准备工作如下在app.json中添加 watch页面代码watch.wxmlwatch.wxsswatch.js connect导航页面使用在腾讯位置服务需要获取key地图选点当用户未点击选址时&#xff0c;默认传入用户当前地址&#xff0c;可以在onShow方法中定义 代码解读 …

微信小程序——地图(定位,多个标记点)

效果图 指定为位置 Page({data: {longitude: 113.14278, //地图界面中心的经度latitude: 23.02882, //地图界面中心的纬度markers: [ //标志点的位置//位置0{id: 0,iconPath: "../images/1.png",latitude: 23.04308268848755,longitude: 113.13562655285273,width: …