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); //建立套接字,基于TCP
    int 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_INET
        u_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;
    
    //建立socket
    iSocketFD = 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*/
    
    //绑定地址结构体和socket
    if(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" //目标地址IP
 
int main()
{
    int iSocketFD = 0; //socket句柄
    unsigned int iRemoteAddr = 0;
    struct sockaddr_in stRemoteAddr = {0}; //对端,即目标地址信息
    socklen_t socklen = 0;  	
    char buf[4096] = {0}; //存储接收到的数据
    
    //建立socket
    iSocketFD = 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32基础回顾

文章目录 单片机编程的原理GPIO中断EXTI外部中断定时器中断、串口中断 定时器定时器中断配置过程通用定时器输出比较功能&#xff1a;PWM波的生成定时器的输入捕获功能主从触发模式PWMI模式 定时器的编码器接口 DMA简介通信接口USART软件配置流程&#xff1a;1、仅发数据的配置…

校园跑腿小程序功能分享

提起校园跑腿小程序大家都不陌生&#xff0c;尤其是对上大学的伙伴们来说,更是熟悉得不能再熟悉了&#xff0c;和我们的生活息息相关&#xff0c;密不可分。 对于现在的年轻人来说&#xff0c;网购是非常简单和方便的一种购物方式&#xff0c;随之快递也会越来越多。在我们国家…

java版本spring cloud 企业工程系统管理 工程项目管理系统源码

&#xfeff; Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&…

self-attention笔记

self-attention 对于self-attention的理解 对于self-attention&#xff0c;我们直觉可能会觉得是从一个大的数据中&#xff0c;将我们的注意力集中在我们感兴趣的区域里&#xff0c; 但通过self-attention的原理可以发现&#xff0c;其原理更像是对于一个区域&#xff08;一个…

八大排序算法--希尔排序(动图理解)

目录 希尔排序 概念 算法思路 动画演示 代码如下 复杂度分析 时间复杂度测试 运行结果 完整代码 创作不易&#xff0c;如果本篇博客对您有一定的帮助&#xff0c;大家记得留言点赞哦。 希尔排序 概念 希尔排序是插入排序的一种&#xff0c;是对直接插入排序的优化。其…

uniapp小程序,根据小程序的环境版本,控制的显页面功能按钮的示隐藏

需求&#xff1a;根据小程序环境控制控制页面某个功能按钮的显示隐藏&#xff1b; 下面是官方文档和功能实现的相关代码&#xff1a; 实现上面需要&#xff0c;用到了uni.getAccountInfoSync()&#xff1a; uni.getAccountInfoSync() 是一个 Uniapp 提供的同步方法&#xff0c…

Acwing.875 快速幂

题目 给定n组ai , bi, pi&#xff0c;对于每组数据&#xff0c;求出akimod pi的值。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含三个整数ai , bi,pi。输出格式 对于每组数据&#xff0c;输出一个结果&#xff0c;表示aibimod pi的值。 每个结果占一行。 数…

Linux - 环境变量

1.基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但 是照样可以链接成功&#xff0c;生…

「如何优雅有效利用周末和下班时间?」

文章目录 每日一句正能量前言下班的时间规划周末的时间规划提升周末体验感的好方法怎样才能获得充分的休息后记 每日一句正能量 眼望古城街尽&#xff0c;心谱落愁无序&#xff0c;旧时的誓言&#xff0c;曾而相似&#xff0c;河水在遵循河道的指引下&#xff0c;在曲折前进中放…

zookeeper学习(三)基础数据结构

数据模型 在 zookeeper 中&#xff0c;可以说 zookeeper 中的所有存储的数据是由 znode 组成的&#xff0c;节点也称为 znode&#xff0c;并以 key/value 形式存储数据。 整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 / 开头。 进入 zookeeper 安装的 …

心法利器[93] | 谈校招:技术面

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会&#xff0c;与大家一起成长。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2022年新一版的文章合集已经发布&#xff0c;累计已经60w字了&#xff0c;获取方式看这里&…

大数据面试题:HBase的RegionServer宕机以后怎么恢复的?

面试题来源&#xff1a; 《大数据面试题 V4.0》 大数据面试题V3.0&#xff0c;523道题&#xff0c;679页&#xff0c;46w字 可回答&#xff1a;1&#xff09;HBase一个节点宕机了怎么办&#xff1b;2&#xff09;HBase故障恢复 参考答案&#xff1a; 1、HBase常见故障 导…

抖音短视频seo矩阵系统源码开发部署技术分享

抖音短视频的SEO矩阵系统是一个非常重要的部分&#xff0c;它可以帮助视频更好地被搜索引擎识别和推荐。以下是一些关于开发和部署抖音短视频SEO矩阵系统的技术分享&#xff1a; 一、 抖音短视频SEO矩阵系统的技术分享&#xff1a; 关键词研究&#xff1a;在开发抖音短视频SEO矩…

助力保险行业数字化创新,麒麟信安参展2023中国财险科技应用高峰论坛

2023年7月27日&#xff0c;由中科软科技股份有限公司主办的“中国财险科技应用高峰论坛”在北京古北水镇成功举办。作为享誉中国保险科技界的盛会&#xff0c;本次活动以“数智保险 创新未来”主题&#xff0c;汇聚全国数百位保险公司主管领导、资深保险行业信息化专家&#xf…

【探讨】Java POI 处理 Excel 中的名称管理器

前言 最近遇到了一些导表的问题。原本的导表工具导不了使用名称管理器的Excel。 首先我们有两个Sheet。B1用的是名称管理器中的AAA, 而B2用的对应的公式。 第二个sheet&#xff0c;名为Test2: 这是一段简化的代码&#xff1a; public class Main {public static void mai…

Stable Diffusion - 真人照片的高清修复 (StableSR + GFPGAN) 最佳实践

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132032216 GFPGAN (Generative Facial Prior GAN) 算法&#xff0c;用于实现真实世界的盲脸恢复的算法&#xff0c;利用预训练的面部 GAN&#xf…

61 # http 数据处理

node 中的核心模块 http 可以快速的创建一个 web 服务 const http require("http"); const url require("url");// req > request 客户端的所有信息 // res > respone 可以给客户端写入数据 const server http.createServer();server.on("r…

Linux虚拟机中安装MySQL5.6.34

目录 第一章、xshell工具和xftp的使用1.1&#xff09;xshell下载与安装1.2&#xff09;xshell连接1.3&#xff09;xftp下载安装和连接 第二章、安装MySQL5.6.34&#xff08;不同版本安装方式不同)2.1&#xff09;关闭防火墙&#xff0c;传输MySQL压缩包到Linux虚拟机2.2&#x…

【Docker 学习笔记】Docker架构及三要素

文章目录 一、Docker 简介二、Docker 架构1. Docker 客户端和服务器2. Docker 架构图3. Docker 运行流程图 三、Docker 三要素1. 镜像&#xff08;Image&#xff09;2. 容器&#xff08;Container&#xff09;3. 仓库&#xff08;Repository&#xff09; 一、Docker 简介 Dock…

解决el-table打印时数据重复显示

1.表格数据比较多加了横向滚动和竖向滚动&#xff0c;导致打印出问题 主要原因是fixed导致&#xff0c;但是又必须得滚动和打印 方法如下&#xff1a; 1. 2. is_fixed: true,//data中定义初始值 3.打印时设置为false,记得要改回true if (key 2) { this.is_fixed false //打…