流式套接字基本概念

article/2025/10/20 20:49:03

目录

  • 流式套接字基本概念
    • 创建套接字
    • 绑定本地地址
    • 连接请求
    • 监听函数
    • 接收请求
    • 套接字IO操作
    • 关闭套接字
  • 编程实现

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制

流式套接字基本概念

在这里插入图片描述

创建套接字

int socket(int domain,int type,int protocol);
返回值:文件描述符表示成功,-1表示错误,errno记录错误代码
  • 套接字的域名domain
    代表套接字的地址族

    域名地址族
    AF_UNIX,AF_LOCAL用于本地通信
    AP_INET,PF_INETIPv4,Internet协议
    AF_INET6IPv6,Internet协议
    AF_IPXNovell网络协议
  • 套接字的类型type

    最常用的两个值是SOCK_STREAMSOCK_DGRAM

    1. SOCK_STREAM流式套接字

      流式套接字不保留任何消息的边界,他只是简单的将它所有的数据交给接收方。

      此外,数据严格按照写入时的顺序被接收端所读取。在IP协议中,分组可以按照不同的路由被转发到目的地,因此在数据接受端会发生分组失序现象,而流式套接字可以保证接收端按照数据发送时的顺序正确接收到数据。如果传输时发生错误,则流式传输机制自动进行差错校正。

      流式套接字提供的是可靠地数据连接,采用面向连接的方式。

    2. SOCK_DGRAM数据报套接字

      用于无连接通信,即通信前双方不需要建立任何连接,只要创建了一个非连接的数据报套接字。

      UDP协议就是典型的数据报通信方式。

      数据报套接字不知道传输过程中是否发生了数据丢失>,因此对于数据差错的发现和纠正只能通过应用层来保证。

  • 使用的协议protocol

    一般情况为0,代表由系统在当前设定的domain下,自动选择适合的协议类型。

绑定本地地址

创建套接字后,该套接字处于未和任何协议地址关联的状态。

如果位于两个不同主机的套接字需要连接而又无地址,那他们无法通信。因此使用bind()将套接字绑定到指定的协议族。

int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
返回值:0表示成功,-1表示失败,errno记录错误代码
  • sockfd

    使用socket()函数返回的结果

  • myaddr

    分配给套接字的地址指针.

    struct sockaddr{//通用套接字地址sa_family_t sa_family;//地址族char        sa_data[4];//地址数据
    }
    不会直接使用该结构进行地址设置,他只是作为一个通用类型,以确定所有其他具体地址的结构、
    
    IPv4套接字地址
    struct sockaddr_in{sa_family_t sin_family;//地址族uint16_t sin_port;//端口struct in_addr sin_addr;//ip地址unsigned char sin_zero[8];//占位字节
    }
    struct in_addr{uint32_t s_addr;//IP地址
    }
    
  • addrlen

    myaddr地址的长度

注意,服务器端需要绑定,而客户端不需要。因为通常都是客户端主动发起的连接请求,因此客户端套接字在发出连接请求后,由内核自动绑定到一个临时端口和地址上。而作为服务器,一般是工作在被动连接的方式下,所以必须通过显示的调用bind(),将监听套接字绑定到一个众所周知的端口上,以等待客户端的连接。

连接请求

int connect(int sockfd,const struct sockaddr *servaddr,socklen_t addrlen);
返回值:0表示成功。-1表示失败,errno记录错误代码

用于TCP客户端和TCP服务器建立连接。

  • sockfd

    调用socket()生成的套接字

  • servaddr

    客户端准备连接的服务器地址

  • addrlen

    服务器地址长度

监听函数

int listen(int sockfd,int backlog);
返回值:0成功,-1失败。errno记录错误代码

用于TCP服务器启动监听

  • sockfd

    用于监听的套接字

  • backlog

    连接队列的长度。是指完成TCP三次握手之后已经成功建立TCP连接的队列长度。服务器执行accept()操作时,从该队列中取下一个连接进行后续处理。默认是128

接收请求

int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);
返回值:文件描述符表示成功,-1表示失败merrno记录错误代码
  • sockfd

    用于监听的套接字

  • cliaddr

    用于接收客户端套接字地址的地址结构指针。

  • addrlen

    指向接收套接字地址缓存最大长度的指针。

如果函数调用成功,他的返回值是一个新的套接字描述符,称为连接套接字,服务器使用该套接字和已经建立连接的客户端进行通信。而原有的监听套接字继续接收后续新客户端发来的连接请求。连接套接字在通信完毕后关闭,但监听套接字会一直监听直到整个应用结束。

在这里插入图片描述

套接字IO操作

ssize_t read(int sockfd,void *buf, size_t count);
返回:非0 是所读字节数。0文件尾,-1失败, errno记录错误代码
  • sockfd

    用于读操作的套接字

  • buf

    用于存放读入数据的缓存

  • count

    代表本次read可以接收的最大可读数据字节长度,通常是buf指向缓存的大小。

ssize_t write(int sockfd,const void *buf,size_t count);
返回值:非0表示所写字节数,0表示未写任何数据,-1表示失败,errno记录错误代码、
  • sockfd:用于写操作的套接字
  • buf:存放被写数据的缓存
  • count:被写数据字节的长度,通常为buf指向的输出缓存的大小。

关闭套接字

int close(int sockfd);
int shutdown(int sockfd,int how);
0表示成功.-1失败
前者完全关闭,后者用于希望在完全关闭本地套接字前仍然可以从远端套接字继续接收数据,但不允许本地发送。通常用于即将结束通信的善后处理。

参数how

说明
0SHUT_RD不允许本地socket进行读操作
1SHUT_WR不允许本地socket进行写操作
2SHUT_RDWR等于close

编程实现

wins下,cygwin

服务器端
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define BUFSIZE 512
int main(int argc,char *argv[]){int sockfd;//服务器套接字 int new_sockfd;//连接套集字 struct sockaddr_in server_addr;//服务器地址 sockaddr_in ipV4 struct sockaddr_in client_addr;//客户端地址socklen_t size;int portnumber;//端口号 char reqBuf[BUFSIZE];//接收缓存区int z;//read()返回值if(argc!=2){fprintf(stderr, " %s portnumber\n",argv[0] );exit(1);}if((portnumber=atoi(argv[1]))<0){fprintf(stderr, "%s portnumber\n",argv[0]);exit(1);}if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1){fprintf(stderr, "socket errot:%s\n",strerror(errno));exit(1);}memset(&server_addr,0,sizeof server_addr);server_addr.sin_family=AF_INET;//IP V4 协议族server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//host ip->net ,long typeserver_addr.sin_port=htons(portnumber);// 端口if((bind(sockfd,(struct sockaddr *)(&server_addr),sizeof server_addr))==-1){//绑定套接字到指定地址和端口fprintf(stderr, " bind error: %s\n",strerror(errno));exit(1);}if(listen(sockfd,128)==-1){//监听请求,将请求放入BackLog中,队列fprintf(stderr, " listen error:%s\n",strerror(errno));exit(1);}printf("wait for the request from client\n");while(1){size=sizeof(struct sockaddr_in);if((new_sockfd=accept(sockfd,(struct sockaddr *)(&client_addr),&size))==-1){fprintf(stderr, "accept error:%s\n", strerror(errno));}fprintf(stdout, "server got connection from %s\n", inet_ntoa(client_addr.sin_addr));while(1){//接收数据z=read(new_sockfd,reqBuf,sizeof reqBuf); if(z<0){fprintf(stderr, "read error:%s\n",strerror(errno));exit(1);}if(z==0){printf("colse new_sockfd\n");close(new_sockfd);break;}reqBuf[z]=0;printf("receive form client:   %s\n",reqBuf);printf("write down your message to client\n");fgets(reqBuf,sizeof reqBuf,stdin);z=write(new_sockfd,reqBuf,sizeof reqBuf);if(z<0){printf("write error");exit(1);}}}
}
客户端#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define BUFSIZE 512
int main(int argc,char *argv[]){int sockfd;char buf[BUFSIZE];struct sockaddr_in server_addr;struct hostent *host;int portnumber;int nbytes;int z;char reqBuf[BUFSIZE];host=gethostbyname(argv[1]);portnumber=atoi(argv[2]);if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1){fprintf(stderr, "socket error:%s\n", strerror(errno));exit(1);}memset(&server_addr,0,sizeof server_addr);server_addr.sin_family=AF_INET;server_addr.sin_port=htons(portnumber);server_addr.sin_addr=*((struct in_addr*)host->h_addr);if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof server_addr)==-1){fprintf(stderr, "connect error:%s\n", strerror(errno));exit(1);} printf("connect success!\n");while(1){printf("please input your message to server\n");if(!fgets(reqBuf,sizeof reqBuf,stdin)){printf("fgets error!\n");break;}z=strlen(reqBuf);if(z>0&&reqBuf[--z]=='\n')//末尾添加NULL,同时去掉\n reqBuf[z]=0;if(z==0) continue;//input QUIT to exitif(!strcasecmp(reqBuf,"QUIT")){printf("the client colsed.please enter any key to exit\n");getchar();write(sockfd,reqBuf,strlen(reqBuf));break;} z=write(sockfd,reqBuf,strlen(reqBuf));if(z<0){fprintf(stderr, "write error:%s\n",strerror(errno));exit(1);}if((z=read(sockfd,reqBuf,sizeof(reqBuf)))==-1){fprintf(stderr, "read error:%s\n",strerror(errno));			exit(1);}if(z==0){printf("the server colsed.please enter any key to exit\n");getchar(); break;} reqBuf[z]=0;printf("reveice message:%s\n",reqBuf);}close(sockfd);return 0;
}

编译之后,先运行服务器端,然后再打开客户端。通信端口是9000.
左边服务器端,右边客户端(写自己本地IPv4地址,打开CMD,输入IPCONFIG可以看到)
在这里插入图片描述在这里插入图片描述

在这里插入图片描述客户端输入quit退出。然后服务器listen到新的连接时,之前accept产生的套接字关闭了。开始新的连接。

参考于:《网络编程与分层协议设计-刘飚》


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

相关文章

Windows下套接字

一、套接字 windows套接字Socket是进程通信的一种方式&#xff0c;可以实现在不同主机的相关进程之间交换数据。在TCP/IP网络应用中&#xff0c;通信的两个进程的主要模式是客户/服务器(C/S)模式&#xff0c;即客户向服务器发出请求&#xff0c;服务器接受到请求后&#xf…

深入理解Socket套接字原理

Socket套接字原理 1、什么是Socket 在计算机领域&#xff0c;套接字Socket作为计算机之间进行通信的固定的约定方式之一存在。这种太抽象了&#xff0c;我举个例子&#xff0c;我们要是用笔记本电脑前需要先对电脑供电&#xff0c;那供电就有两种方式电线插座供电和电池供电&…

原始套接字

一、原始套接字概述 协议栈的原始套接字从实现上可以分为“链路层原始套接字”和“网络层原始套接字”两大类。 链路层原始套接字可以直接用于接收和发送链路层的MAC帧&#xff0c;在发送时需要由调用者自行构造和封装MAC首部。而网络层原始套接字可以直接用于接收和发送IP层…

socket套接字

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 socket套接字 1. 什么是socket套接字2. socket编程3. 网络字节序4. IP地址转换函数5. sockaddr数据结构…

java 套接字是什么_套接字是什么,套接字通信及其原理

为通信的端点,每个套接字由一个 IP 地址和一个端口号组成。通过网络通信的每对进程需要使用一对套接字,即每个进程各有一个。 通常,套接字采用客户机-服务器架构。服务器通过监听指定端口,来等待客户请求。服务器在收到请求后,接受来自客户套接字的连接,从而完成连接。 实…

网络编程——原始套接字实现原理

目录 1. 基础知识 1.1、概述 1.2、链路层原始套接字 1.3、网络层原始套接字 2、原始套接字的实现 2.1 原始套接字报文收发流程 2.2链路层原始套接字的实现 2.2.1 套接字创建 2.2.2 报文接收 2.2.3 报文发送 2.2.4 其它 2.3 网络层原始套接字的实现 2.3.1 套接字…

UDP套接字编程

参考&#xff1a;《UNIX 网络编程 卷1 : 套接字联网API》 UDP 与 TCP 之间传输存在差异&#xff0c;也导致编写应用程序存在很多差异。UDP 客户端和服务器不建立连接&#xff0c;而是直接使用 sendto 函数给服务器发送数据报。但必须指定目的地的地址作为参数。服务器也不用接…

网络套接字编程

网络套接字编程 一、 认识UDP协议 UDP(User Datagram Protocol 用户数据报协议&#xff0c;是不可靠的数据报传输协议&#xff0c;不确保数据安全有序的到达对端。 特点&#xff1a; 传输层协议无连接不可靠传输面向数据报 应用场景&#xff1a;性能要求大于安全要求&…

彻底弄懂套接字

1.什么是套接字&#xff08;英文名&#xff1a;插座&#xff09; 套接字&#xff08;socket&#xff09;是一种通信机制&#xff0c;凭借这种机制&#xff0c;客户/服务器系统的开发工作既可以在本地单机上进行&#xff0c;也可以跨网络进行。Linux所提供的功能&#xff08;如打…

什么是套接字?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: 石家庄市长安公园人民广场, /*这…