socket 基础

Socket是什么呢?

① Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过“套接字”向网络发出请求或者应答网络请求。

② Socket是连接运行在网络上的两个程序间的双向通信的端点。

③ 网络通讯其实指的就是Socket间的通讯。

④ 通讯的两端都有Socket,数据在两个Socket之间通过IO来进行传输。

或者更通俗的解释: socket = ip + port

Socket原理?

基于tcp连接的socket 连接图
在这里插入图片描述
在这里插入图片描述

流式传输:“客户端”,
1.socket()函数;
2.bind()函数可有可无,加上指定传输端口,不加随机分配端口;
3.connect()函数,填写服务端的地址与端口【网络间通信AF_STREAM】或者路径【进程间通信AF_DGRAM】;
4.send()函数;
5.recv()函数。流式传输:“服务端”,
1.socket()函数;
2.bind()函数,必须加上指定传输端口【网络间通信AF_STREAM】或者是路径【进程间通信AF_DGRAM】;
3.listen()函数,使用isockfd;
5.accepc()函数,生成新的fd,inewfd;
6.send()函数,inewfd;
7.recv()函数,inewfd。

socket 接口函数

#include<sys/socket.h>//socket 函数
int socket(int domain, int type, int protocol)第一个参数domain指明了协议族,通常用AF_INET、AF_INET6、AF_LOCAL等。AF表示地址族,选择 AF_INET 的目的就是使用 IPv4 进行通信。因为 IPv4 使用 32 位地址,相比 IPv6 的 128 位来说,计算更快,便于用于局域网通信。第二个参数type是Socket类型,常用的Socket类型我们之前已经介绍过了分别是SOCK_STREAM和SOCK_DGRAM因为我们要写的是TCP Socket编程所以我们使用SOCK_STREAM。第三个参数protocol表示传输协议一般取为0。因为一般情况下有了 domain和 type 两个参数就可以创建套接字了,操作系统会自动推演出协议类型,除非遇到这样的情况:有两种不同的协议支持同一种地址类型和数据传输类型。如果我们不指明使用哪种协议,操作系统是没办法自动推演的。example:int sockfd = socket(AF_INET, SOCK_STREAM, 0); //建立套接字,基于TCPint sockfd = socket(AF_INET, SOCK_DGRAM, 0); //基于UDP
/=====================================================================///bind  函数  
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 第一个参数sockfd为上一步创建socket时的返回值。第二个参数addr 为 sockaddr 结构体变量的指针。该类型的定义原型如下:struct sockaddr_in {short   sin_family;    //协议族,与前面Socket函数中提到的一样,我们这里使用AF_INETu_short sin_port;        //端口号,需要struct in_addr sin_addr;    //IP地址,需要使用网络序char    sin_zero[8];    //没有实际意义,只是为了跟SOCKADDR结构在内存中对齐};第三个参数addrlen为addr 变量的大小,可由 sizeof() 计算得出。example:struct sockaddr_in serv_addr;    //创建结构体变量servaddr.sin_family=AF_INET;    //sin_family指代协议族和前面讲述socket()的第一个参数的含义相同,取值也需跟socke函数第一个参数值一样。servaddr.sin_port=htons(2000);    //sin_port存储端口号(使用网络字节顺序,对于htons()函数我们还有单独一章的说明,2000这个端口转换为网络字节序列。//理论上端口号的取值范围为是0到65536,但0到1023的端口一般由系统分配给特定的服务程序,比如Web 服务的端口号为 80所以我们的程序要尽量在 1024~65536 之间分配端口号。servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");    //将iP地址127.0.0.1也就是本机地址转换为十进制bind(sockfd,(sockaddr*)&servaddr,sizeof(servaddr));    // 将套接字绑定到本地地址和端口上。
/=====================================================================///listen函数
int listen(int sockfd, int n);第一个参数为第一步sockfd创建socket时的返回值,套接字的描述符。第二个参数n用于指定接收队列的长度,也就是在Server程序调用accept函数之前最大允许进入的连接请求数,多余的连接请求将被拒绝,典型取值为5。example:listen(sockfd,5);//监听sockfd为创建套接字时的返回值。
/=====================================================================///accept函数        
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);sockfd为建立socket函数返回的值。addr为 sockaddr 结构体变量的指针,这个参数是指针类型,是向外传内容的,即addr将在函数调用后填入对方(客户端)的地址信息,如对方的IP、端口等。addrlen为 addr变量的大小,可由 sizeof() 计算得出。   example:struct sockaddr_in clientaddr//创建客户端地址结构体int aID;//用来接收accept函数返回值aID = accept(sockfd,(sockaddr*)&clientaddr, sizeof( clientaddr));//等待接收客户连接请求
/=====================================================================///connect函数 
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);sockfd:socket文件描述符addr:传出参数,返回链接客户端地址信息,含IP地址和端口号addrlen:传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小example:struct sockaddr_in server_addr;int cfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;inet_pton(AF_INET, CLIENT_IP, &server_addr.sin_addr.s_addr);server_addr.sin_port = htons(6666);connect(cfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
/=====================================================================///recv函数(tcp) & recvfrom( 通常用于UDP)
int recv (int fd, void *buf, int n, int flags);第一个参数fd,表示连接成功的套接字描述符。注意:这一步对于服务端而言是上一步accept的返回值;对于客户端而言是connect的返回值,并非是第一步socket创建套接字的返回值,不要搞混!第二个参数buf,就是为要接收的数据所在的缓冲区地址,也就是一个空的字符数组的首地址,这里放结果。第三个参数len为要接收数据的字节数。第四个参数flags为发送数据时的附带标记 ,一般情况下设置为0。但可以选择下列设置:MSG_DONTROUTE:表示不使用指定路由,对send、sendto有效MSG_PEEK:对recv, recvfrom有效,表示读出网络数据后不清除已读的数据MSG_OOB:对发送接收都有效,表示发送或接受加急数据example:char recBuf[200];//定义一个字符串用来保存客户端发来的数据recv(fd,recBuf,200,0);//接收来自客户端或服务端的数据recv缺省是阻塞函数,直到收到信息或出错才会返回
/=====================================================================///send函数(tcp) & sendto(通常用于UDP)
int send (int fd, const void *buf, int n, int flags);第一个参数fd,表示连接成功的套接字描述符。注意:这一步对于服务端而言是上一步accept的返回值;对于客户端而言是connect的返回值,并非是第一步socket创建套接字的返回值,不要搞混!第二个参数buf为要发送的数据所在的缓冲区地址,即一个已经存好内容的字符数组第三个参数len为要发送的数据的实际字节数+1。第四个参数flags为发送数据时的附带标记 ,一般情况下设置为0。但可以选择下列设置:MSG_DONTROUTE:表示不使用指定路由,对send、sendto有效 MSG_PEEK:对recv, recvfrom有效,表示读出网络数据后不清除已读的数据 MSG_OOB:对发送接收都有效,表示发送或接受加急数据example:char sendBuf[200];//定义一个数组用来保存发送的数据send(fd,sendBuf,strlen(sendBuf)+1,0);//用来发送服务端或客户端的数据与recv同样,send函数缺省也是阻塞函数,直到发送完毕或出错才会返回。需要注意,如果函数返回值与参数len不相等,则剩余未发送的信息需要再次发送/=====================================================================///close函数 && shutdown函数 
int close (int fd);
int shutdown (int fd, int how)    /* how determines what to shut down:SHUT_RD   = No more receptions;SHUT_WR   = No more transmissions;SHUT_RDWR = No more receptions or transmissions.*//=====================================================================/    

socket 类似tcp 的工作原理

在这里插入图片描述
在这里插入图片描述

基于TCP(面向连接)的socket编程——流式套接字(SOCK_STREAM)

server.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>#define PORT 23		//端口号
#define BACKLOG 5	//最大监听数int main()
{int iSocketFD = 0;  //socket句柄int iRecvLen = 0;   //接收成功后的返回值int new_fd = 0; 	//建立连接后的句柄char buf[4096] = {0}; //struct sockaddr_in stLocalAddr = {0}; //本地地址信息结构图,下面有具体的属性赋值struct sockaddr_in stRemoteAddr = {0}; //对方地址信息socklen_t socklen = 0;//建立socketiSocketFD = socket(AF_INET, SOCK_STREAM, 0); if(0 > iSocketFD){printf("创建socket失败!\n");return 0;}	stLocalAddr.sin_family = AF_INET;  /*该属性表示接收本机或其他机器传输*/stLocalAddr.sin_port = htons(PORT); /*端口号*/stLocalAddr.sin_addr.s_addr=htonl(INADDR_ANY); /*IP,括号内容表示本机IP*///绑定地址结构体和socketif(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr))){printf("绑定失败!\n");return 0;}//开启监听 ,第二个参数是最大监听数if(0 > listen(iSocketFD, BACKLOG)){printf("监听失败!\n");return 0;}printf("iSocketFD: %d\n", iSocketFD);	//在这里阻塞知道接收到消息,参数分别是socket句柄,接收到的地址信息以及大小 new_fd = accept(iSocketFD, (void *)&stRemoteAddr, &socklen);if(0 > new_fd){printf("接收失败!\n");return 0;}else{printf("接收成功!\n");//发送内容,参数分别是连接句柄,内容,大小,其他信息(设为0即可) send(new_fd, "这是服务器接收成功后发回的信息!", sizeof("这是服务器接收成功后发回的信息!"), 0);}printf("new_fd: %d\n", new_fd);	iRecvLen = recv(new_fd, buf, sizeof(buf), 0);	if(0 >= iRecvLen)    //对端关闭连接 返回0{	printf("接收失败或者对端关闭连接!\n");}else{printf("buf: %s\n", buf);}close(new_fd);close(iSocketFD);return 0;
}
client.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>#define PORT 23			//目标地址端口号
#define ADDR "192.168.1.230" //目标地址IPint main()
{int iSocketFD = 0; //socket句柄unsigned int iRemoteAddr = 0;struct sockaddr_in stRemoteAddr = {0}; //对端,即目标地址信息socklen_t socklen = 0;  	char buf[4096] = {0}; //存储接收到的数据//建立socketiSocketFD = socket(AF_INET, SOCK_STREAM, 0); if(0 > iSocketFD){printf("创建socket失败!\n");return 0;}	//绑定服务器的ip地址和端口stRemoteAddr.sin_family = AF_INET;stRemoteAddr.sin_port = htons(PORT);inet_pton(AF_INET, ADDR, &iRemoteAddr);stRemoteAddr.sin_addr.s_addr=iRemoteAddr;//connet()连接方法: 传入句柄,目标地址,和大小if(0 > connect(iSocketFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr))){printf("连接失败!\n");//printf("connect failed:%d",errno);//失败时也可打印errno}else{printf("连接成功!\n");recv(iSocketFD, buf, sizeof(buf), 0);//将接收数据打入buf,参数分别是句柄,储存处,最大长度,其他信息(设为0即可)。 printf("Received:%s\n", buf);}close(iSocketFD);//关闭socket	return 0;
}

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

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

相关文章

【Go语言】Golang保姆级入门教程 Go初学者介绍chapter1

Golang 开山篇 Golang的学习方向 区块链研发工程师&#xff1a; 去中心化 虚拟货币 金融 Go服务器端、游戏软件工程师 &#xff1a; C C 处理日志 数据打包 文件系统 数据处理 很厉害 处理大并发 Golang分布式、云计算软件工程师&#xff1a;盛大云 cdn 京东 消息推送 分布式文…

【RabbitMQ】golang客户端教程2——工作队列

任务队列/工作队列 在上一个教程中&#xff0c;我们编写程序从命名的队列发送和接收消息。在这一节中&#xff0c;我们将创建一个工作队列&#xff0c;该队列将用于在多个工人之间分配耗时的任务。 工作队列&#xff08;又称任务队列&#xff09;的主要思想是避免立即执行某些…

pip安装lap出现问题

解决方法一 用conda安装&#xff0c;用以下命令&#xff1a; conda install -c conda-forge lap解决方法二 用pip安装&#xff0c;用以下命令&#xff1a; pip install gitgit://github.com/gatagat/lap.git文章目录 解决方法一解决方法二摘要YoloV8改进策略&#xff1a;基…

短视频矩阵源码

一、短视频矩阵源码搭建解析&#xff1a; 目录 一、短视频矩阵源码搭建解析&#xff1a; 二、短视频矩阵源码的开发路径分享&#xff1a; 三、短视频矩阵系统开发应具备哪些能力&#xff1f; 短视频技术开发能力&#xff1a; 开发人员应具备短视频相关技术能力&#xff0c…

Vcenter 创建 虚拟机配置 Thin Provision 模式 disk

介绍 在vCenter中选择虚拟磁盘格式通常也取决于您的需求和使用情况。 vSphere支持多种虚拟磁盘格式&#xff0c;以下是一些常见的格式&#xff1a; Thick Provision Lazy Zeroed&#xff1a;这是vSphere中的默认格式。它会预分配虚拟磁盘所需的存储空间&#xff0c;但只有在虚…

深度学习(32)——CycleGAN

深度学习&#xff08;32&#xff09;——CycleGAN 文章目录 深度学习&#xff08;32&#xff09;——CycleGAN1. GAN原理2. CycleGAN&#xff08;1&#xff09;原理&#xff08;2&#xff09;核心思想&#xff08;3&#xff09;优点&#xff08;4&#xff09;缺点&#xff08;5…

安全测试国家标准解读——并发程序安全

本系列文章主要围绕《GB/T 38674—2020 信息安全技术 应用软件安全编程指南》进行讲解&#xff0c;该标准是2020年4月28日&#xff0c;由国家市场监督管理总局、国家标准化管理委员会发布&#xff0c;2020年11月01日开始实施。我们对该标准中一些常见的漏洞进行了梳理&#xff…

2023最新Ubuntu安装部署Gitlab详细教程(每个步骤均配图)

Ubuntu安装配置Gitlab详细步骤 安装依赖 打开终端&#xff0c;运行如下命令&#xff1a; sudo apt updatesudo apt-get upgradesudo apt-get install curl openssh-server ca-certificates postfix接下来会遇到如下界面&#xff0c;Tab切换到“确定”按钮&#xff0c;然后回…

Tomcat 安装配置教程及成功后,启动失败报错解决方案

解决方案 我的报错原因是因为我的JDK是1.8的而我的Tomcat是10版本的&#xff0c;可能是因为版本原因吧&#xff0c;我重新装了Tomcat 9就可以启动成功了&#xff01; 简单说下安装的时候需要注意哪些步骤吧 今天我在安装tomcat10的时候&#xff0c;安装成功后&#xff0c;启…

RT1052的定时器

文章目录 1 通用定时器1.1 定时器框图1.2 实现周期性中断 2 相关寄存器3 定时器配置3.1 时钟使能3.2 初始化GPT1定时器3.2.1 base3.2.2 initConfig3.2.2.1 clockSorce3.2.2.2 divider3.2.2.3 enablexxxxx 3.3 设置 GPT1 比较值3.3.1 base3.3.2 channel3.3.3 value 3.4 设置 GPT…

AD21 PCB设计的高级应用(三)PCB多板互连装配设计

&#xff08;三&#xff09;PCB多板互连装配设计 一旦模块在多板原理图上相互连接,就可以验证板到板的连接。这将检测网络到引脚分配错误和引脚到引脚的互连布线错误。可以解决这些错误并将修改信息更新到对应的 PCB 中,或者重新更新到源系统原理图。 印制电路板不是孤立存在的…

uni-app如何生成正式的APK

第一步&#xff1a; 进入dcloud官网https://dcloud.io/&#xff0c;点击开发者后台进入登录注册页面 第二步&#xff1a;登录之后跳到项目列表&#xff0c;选择自己想要打包的项目 点击进去如果没有生成证书&#xff0c;点击生成证书&#xff0c;如果显示证书已生成就不用管了…

OpenJDK下载安装教程

《OpenJDK官网》 进入官网&#xff0c;点击Installing----》jdk.java.net 随便进去一个JDK版本 根据自己的操作系统下载对应的二进制JDK即可&#xff08;我的是Windows&#xff09; 配置环境变量 JAVA_HOME 你的JDK路径\jdk-17PATH追加内容 WINR输入CMD java -version

参数量仅有50KB的超轻量级unet变种网络egeunet【参数和计算量降低494和160倍】医疗图像分割实践

今天看到一篇挺有意思的文章&#xff0c;做的是跟医疗图像分割相关的工作&#xff0c;但是不像之前看到的一些工作一味地去追求高精度&#xff0c;因为医疗领域本身就是一个相对特殊的行业&#xff0c;对于模型产生的结果的精确性要求是很高的&#xff0c;带来的是参数量级的庞…

【Vue】在el-table的el-table-column中,如何控制单行、单列、以及根据内容单独设置样式。例如:修改文字颜色、背景颜色

用cell-style表属性来实现。在官网中是这样表述这个属性的。 在el-table中用v-bind绑定此属性。&#xff08;v-bind的简写是&#xff1a;&#xff09; <el-table:data"options":cell-style"cell"><el-table-column prop"id" label"…

文心一言 VS 讯飞星火 VS chatgpt (68)-- 算法导论6.5 7题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;68&#xff09;-- 算法导论6.5 7题 七、试说明如何使用优先队列来实现一个先进先出队列&#xff0c;以及如何使用优先队列来实现栈(队列和栈的定义见 10.1 节。) 文心一言&#xff1a; 优先队列是一种数据结构&#xff0c;其中…

Python基于PyTorch实现卷积神经网络回归模型(CNN回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 卷积神经网络&#xff0c;简称为卷积网络&#xff0c;与普通神经网络的区别是它的卷积层内的神经元只覆…

【前端知识】React 基础巩固(四十一)——手动路由跳转、参数传递及路由配置

React 基础巩固(四十一)——手动路由跳转、参数传递及路由配置 一、实现手动跳转路由 利用 useNavigate 封装一个 withRouter&#xff08;hoc/with_router.js&#xff09; import { useNavigate } from "react-router-dom"; // 封装一个高阶组件 function withRou…

Stable Diffusion 使用教程

环境说明&#xff1a; stable diffusion version: v1.5.1python: 3.10.6torch: 2.0.1cu118xformers: N/Agradio: 3.32.0 1. 下载 webui 下载地址&#xff1a; GitHub stable-diffusion-webui 下载 根据自己的情况去下载&#xff1a; 最好是 N 卡&#xff1a;&#xff08;我的…

K8S:容器日志收集与管理

Kubernetes 里面对容器日志的处理方式&#xff0c;都叫作 cluster-level-logging&#xff0c;即&#xff1a;这个日志处理系统&#xff0c;与容器、Pod 以及 Node 的生命周期都是完全无关的。这种设计当然是为了保证&#xff0c;无论是容器挂了、Pod 被删除&#xff0c;甚至节点…