套接字+网络套接字函数+客户端大小写程序

news2025/1/11 0:39:41

NAT映射

一般来说:源主机和目的主机都属于局域网,也就是ip地址可能相同

但是:路由器一般是公网ip,即整个网络环境可见

每一个路由器会维护一个NAT映射表

  • 路由器的ip一般是固定的公网ip
  • 路由器与把与它相连的主机:私有ip+端口号映射成路由器ip+端口号

此时再进行数据传输时:会用映射后的ip作为源地址,也就是保护了私有ip

打洞机制

首先进行通信的进程,需要经过路由器到达提供服务的服务器,然后服务器进行拆包后,帮助完成一次转发,再经过多跳路由器后,将信息传递给目的ip

也就是传输的数据包必须途径服务器

由于路由器具有保护机制-----第一次给路由器发送数据包的ip,会被路由器丢弃或屏蔽(防止恶意攻击)

所以,相互通信的ip,要被路由器识别为熟悉的ip才可以直接通信

  • 主机和提供服务的服务器之间是可以直接通信的
  • 所以服务器在请求服务时候,会在两台想建立通信的主机之间,把其相连的路由器标记为熟悉
  • 这样服务器通过打洞机制就相当于在两台主机间建立了通路

几种访问机制(注意不是局域网(内网)之间)

  1. 公网ip和公网ip之间进行通信,直接访问
  2. 公网ip和私网ip之间进行通信,路由器要将私网ip进行NAT映射后,进行通信
  3. 私网ip和私网ip之间进行通信,公有服务器对相连服路由器进行打洞机制,然后通信

套接字

  • Socket本身有“插座”的意思
  • 在Linux环境下,用于表示进程间网络通信的特殊文件类型
  • 本质为内核借助缓冲区形成的伪文件

注意socket一定有两端,成对出现:

数据发送端和数据接收端

就像插电,既要有插头有要求插排

IP地址:在网络环境中,唯一标识一台主机

端口号:主机中唯一标识一个进程

IP+port:在网络环境中,唯一标识一个进程,把这个叫成socket

管道

管道一定有两端,一端只能读,一端只能写,每端分别用一个文件描述符指向

数据只能从写段流入,从读端流出

socket

每次创建一个socket,都有一个文件描述符指向,但是这一个文件描述符由两个缓冲区指向

一个缓冲区用于读数据,一个缓冲区用于写数据,也就是全双工

两个socket是通过ip+port进行连接的

网络字节序

字节序:

  • 也就是字节序

  • 如果数据大于一个字节,在内存中存放是有顺序的

    一般有两种:

    • 小端字节序:将低位字节序存储在低位
    • 大端字节序:将高位字节序存储在低位

其中:TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节

但是,主机中采取的小端字节序

小端存,大端传,所以需要字节序的转换

假设内存:1000 1001 1002 1003 1004

现在的变量:int a=0x12345678(注意位次,←依次升高)

  • 如果采用小端法存储(低位存低,高位存高)

    12是高位存1004,依次:34存1003.。。。。

  • 如果大端就是反过来(78存1004)

网络字节序和主机字节序的转换

#include <arpa/inet.h>
//host to network
//long转IP地址;short转端口号
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
//network to host
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

使用

#include<arpa/inet.h>
int main(){
    int a=0x01020304;
    short int b=0x0102;
    //long转IP地址;short转端口号
    //uint32_t htonl(uint32_t hostlong);
    //uint16_t htons(uint16_t hostshort);
    printf("htonl(0x%08x)=0x%08x\n",a,htonl(a));
    //08表示输出8位,x表示16进制
    printf("htons(0x%08x)=0x%08x\n",b,htonl(b));
    return 0;
}
guojiawei@ubantu-gjw:~/Desktop$ gcc mm.c
guojiawei@ubantu-gjw:~/Desktop$ ./a.out 
htonl(0x01020304)=0x04030201
htons(0x00000102)=0x02010000

ip地址转换

#include <arpa/inet.h>
//ip(点分十进制) to net(网络字节序)
int inet_pton(int af, const char *src, void *dst);
/*
af版本号---只有:AF_INET 和 AF_INET6 两种
src---点分十进制的数值
dst----转换后的整数的地址
*/
#include <arpa/inet.h>
//net to ip(字符串)
const char *inet_ntop(int af, const void *src,  char *dst, socklen_t size);
//dst----点分十进制数串
//size---缓存区的大小

实现:

#include<stdio.h>
#include<arpa/inet.h>
int main(){
    char ip_str[]="172.20.226.11";
    unsigned int ip_uint=0;
    inet_pton(AF_INET,ip_str,&ip_uint);//注意是地址
    printf("ip_uint=%d\n",ip_uint);
    unsigned char* ip_p=NULL;
    ip_p=(unsigned char*)&ip_uint;
    printf("ip_uint=%d.%d.%d.%d\n",*ip_p,*(ip_p+1),\
                          *(ip_p+2),*(ip_p+3) );
    return 0;
} 
#include<stdio.h>
#include<arpa/inet.h>
int main(){
    char ip_str[16]={0};
    unsigned char ip[]={172,20,223,75};
    inet_ntop(AF_INET,(unsigned int*)ip,ip_str,16);
    printf("ip_str=%s\n",ip_str);
    return 0;
} 
//ip_str=172.20.223.75

套接字地址数据结构

sockaddr结构体-----用于描述IPv4协议的地址结构

  • struct sockaddr由于不细致,现在已经不能用了
  • 可是基于sockaddr细分的sockaddr_in无法直接作为socket的网络API的参数,所以需要强制类型转换
struct sockaddr {
               sa_family_t  sa_family;
                      char  sa_data[14];}
struct sockaddr_in {
     sa_family_t    sin_family; /* address family: AF_INET */
     in_port_t      sin_port;   /* port in network byte order */
     struct in_addr sin_addr;   /* internet address */
};
//man 7 ip
/* Internet address. */
struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */};
//由于历史遗留,只有一个成员,每次需要.使用
struct sockaddr_in {
	__kernel_sa_family_t sin_family; 			/* Address family */  	地址结构类型
	__be16 sin_port;					 		/* Port number */		端口号
	struct in_addr sin_addr;					/* Internet address */	IP地址
	/* Pad to size of `struct sockaddr'. */
	unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
	sizeof(unsigned short int) - sizeof(struct in_addr)];
};//详细

使用:

struct sockaddr_in addr;

addr.sin_family=AF_INET//AF_INET6
addr.sin_port=htonl//ntohs
addr.sin_addr.s_addr=htol;ntosl;inet_ptonl;inrt_ntop;

网络套接字函数

socket()

 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>
/*domain:
	AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
	AF_INET6 与上面类似,不过是来用IPv6的地址
	AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
*/
/*type:
       1:SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
       2:SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
       3:SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
*/
/*protocol:
	传0 表示使用默认协议,系统自动选择
	IPPROTO_TCP;IPPROTO_UDP 指定传输tcp或者udp
*/
 int socket(int domain, int type, int protocol);
//成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno

使用

#include <sys/types.h>         
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
    int socketFd=0;
    //创建:使用IPV4地址协议的TCP流式套接字
    socketFd=socket(AF_INET,SOCK_STREAM,0);
    if(socketFd==-1){
        perror("socket()");
        exit(-1);
    }
    else{
        printf("socket has created successfully\n");
    }
    return 0;
}

bind()

 #include <sys/types.h>         
 #include <sys/socket.h>
/*
     sockfd:  socket文件描述符
     addr:     构造出IP地址加端口号
     addrlen:  sizeof(addr)长度
*/
  int bind(int sockfd, const struct sockaddr *addr,\
                        socklen_t addrlen);
//返回值:0表示成功;-1表示失败

bind就是绑定,往套接字上绑定ip和端口号

由于传指针的地址,还得加上大小

#include <sys/types.h>         
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
int main(){
    int socketFd=0;
    //创建:使用IPV4地址协议的TCP流式套接字
    socketFd=socket(AF_INET,SOCK_STREAM,0);
    /*struct sockaddr_in {
           sa_family_t    sin_family; 
           in_port_t      sin_port; 
           struct in_addr sin_addr;  
                 struct in_addr { uint32_t  s_addr;}
    };*/
    struct sockaddr_in my_addr;
    //bzero函数是c++ string.h中的函数。
    //描述:置字节字符串前n个字节为零且包括‘\0’
    bzero(&my_addr,sizeof(my_addr));
    my_addr.sin_family=AF_INET;
    unsigned short port=8000;
    my_addr.sin_port=htons(port);//hton:转换成网络字节序
    my_addr.sin_addr.s_addr=htons(INADDR_ANY);
    int res_bind=bind(socketFd,(struct sockaddr*)&my_addr,sizeof(my_addr));
    printf("res=%d\n",res_bind);
    return 0;
}

listen()

 #include <sys/types.h>       
 #include <sys/socket.h>
/*backlog:
	排队建立3次握手队列和刚刚建立3次握手队列的链接数和
	也就是内核为此套接字建立的最大连接数(同时允许多少个用户端建立连接)
*/
 int listen(int sockfd, int backlog);

listen()仅被TCP通信服务器程序调用,实现监听服务

  • backlog—注意不是指定连接上限数,而是可以建立连接的

accept()

 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>
/*
   addr:
	传出参数,返回链接客户端地址信息,含IP地址和端口号
   addrlen:
	传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小
*/
 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno

三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来

socklen_t *addrlen:

the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address.

connect()

 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>
/*
   addr:
	传入参数,指定服务器端地址信息,含IP地址和端口号
   addrlen:
	传入参数,传入sizeof(addr)大小
*/
int connect(int sockfd, const struct sockaddr *addr,\
                   socklen_t addrlen);
//成功返回0,失败返回-1,设置errno

客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。

socket套接字流程图

比较典型的流程图

实现功能:客户端给服务器发送小写字母,服务器接收后转换成大写字母回传给客户端,然后客户端把内容显示到屏幕上

服务器端:

  • socket创建一个网络套接字
  • bind函数绑定ip地址和端口号(struct sockaddr_in)
  • listen函数来限定同时发起服务器连接的数量
  • accept含有阻塞功能,直到收到了用户的消息才连接

客户端:

  • socket必须绑定ip和端口号才能访问
  • 但是不用bind,会被自动分配,但是服务器端不可以自动分配,客户端无所谓
  • connect进行连接:连接服务器的ip和端口号

客户端程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>//大小写转换
#define SERV_PORT 6667//端口号
int main(void){
    int sfd;
    /*定义accept的客户端的参数*/
    int cfd; 
    char buf[100]={0};
    struct sockaddr_in cline_addr;
    socklen_t clin_addr_len;
    //sockaddr_in结构体定义在头文件:<arpa/inet.h>
    struct sockaddr_in serv_addr;
    sfd=socket(AF_INET,SOCK_STREAM,0);
    /*定义结构体*/
    serv_addr.sin_family=AF_INET;
    //大小端问题:需要hton l是ip;s是端口号
    serv_addr.sin_port=htons(SERV_PORT);
    /*简单方法--------htonl(INADDR_ANY)*/
    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    bind(sfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    /*listen*/
    listen(sfd,32);//最大上限28个客户端
    /*accept---接收一个文件描述符作为参数,最后返回一个文件描述符*/
    clin_addr_len=sizeof(cline_addr);//注意第三个参数:&
    cfd=accept(sfd,(struct sockaddr*)&cline_addr,&clin_addr_len);
    /*连接后:开始读数据*/
    int n=read(cfd,buf,sizeof(buf));//从用户端读
    int i;
    for(i=0;i<n;i++){
        /*小写变大写*/
        buf[i]=toupper(buf[i]);
    }
    write(cfd,buf,n);//写回给数据,别用sizeof
    close(sfd);
    close(cfd);
    return 0;
}

模拟客户端与服务端的通信

//模拟客户端
$ nc -l 端口号
//模拟服务端
$ nc ip地址  端口号

程序运行结果

hello world
HELLO WORLD

--------通信前提是等待,不能一下子就结束

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

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

相关文章

Java-多线程-ThreadPoolExecutor

前言 前面我们讲解线程的时候&#xff0c;讲到了使用Executors创建线程池&#xff0c;但是它里面所有方法可变的参数太少&#xff0c;不能很好的进行自定义设置&#xff0c;以及以后的扩展&#xff0c;更合理的使用cpu线程的操作&#xff0c;所以使用ThreadPoolExecutor创建线程…

SpringBoot集成webservice

前言 之前在工作中&#xff0c;有时候需要去对接第三方的医院&#xff0c;而很多医院的his系统用的都是老技术&#xff08;WebService&#xff09;。一直在对接webservice接口&#xff0c;却不知道webservice接口是怎么实现的&#xff0c;这一次&#xff0c;我们来一探究竟。 …

Android Compose Bloom 项目实战 (一) : 项目说明与配置

1. 项目介绍 Bloom是谷歌 AndroidDevChallenge (Android 开发挑战赛) 中的一期活动&#xff0c;目的是为了推广Compose&#xff0c;非常适合用来练手&#xff0c;通过这个项目&#xff0c;我们可以很好的入门Compose。本文介绍了如何从零开始&#xff0c;开发这个Compose项目。…

计算机系统结构期末复习

名词解释 程序访问局部性 时间局部性是指最近被访问过的数据很可能再次被访问 空间局部性是指最近被访问过的存储空间的附近空间可能会被访问 计算机体系结构 计算机体系结构是程序员所看到的计算机属性&#xff0c;即概念性结构与功能特性 窗口重叠技术 为了能更简单、更直接…

UE5笔记【五】操作细节——光源、光线参数配置、光照图修复

设置光线重载质量模式为预览&#xff1a;可以加快重构速度。 为了更快速高效的学习&#xff0c;直接查看别人已经建好的素材实例。 在EpicGames启动器中打开示例&#xff0c;找到这个照片级渲染。查看别人建好的效果图。 创建工程以UE5版本打开。进入查看。 观察Baked和碰撞测…

MySQL常用函数大全(面试篇)

本篇文章讲解是是MySQL的函数方法&#xff0c;涵盖所有的MySQL常见的方法。主要介绍了面试常问函数。 一、数字函数二、字符串函数三、日期函数四、MySQL高级函数 &#xff08;一&#xff09;数字函数 1、ABS(x) 返回x的绝对值 2、AVG(expression) 返回一个表达式的平均值&am…

Redis分布式锁

1. 什么是分布式锁 分布式锁指的是&#xff0c;所有服务中的所有线程都去获得同一把锁&#xff0c;但只有一个线程可以成功的获得锁&#xff0c;其他没有获得锁的线程必须全部等待&#xff0c;等到获得锁的线程释放掉锁之后获得了锁才能进行操作。 Redis官网中&#xff0c;set…

中加石墨再冲刺港交所上市:2022年初至今收入为零,陈东尧为CEO

11月18日&#xff0c;中加石墨控股股份有限公司&#xff08;下称“中加石墨”&#xff09;在港交所递交招股书&#xff0c;准备在港交所主板&#xff0c;宏信为独家保荐人。据贝多财经了解&#xff0c;这是中加石墨第二次递表&#xff0c;此前曾于2022年2月28日递交上市申请材料…

通过inode结构体取到次设备号,实现LED灯的亮灭

对Linux来说&#xff0c;设备驱动也是文件。驱动控制硬件的过程&#xff0c;实际上是对驱动文件的读写操作。 对内核来说&#xff0c;如何获取唯一的文件标识呢&#xff1f;当然是通过file结构体中的&#xff0c;inode结构体识别应用层打开的到底是哪一个设备文件。 实验操作及…

数据结构题目收录(二十)

1、含有n个非叶结点的m阶B树中至少包含&#xff08;&#xff09;个关键字。 A&#xff1a;n(m1)B&#xff1a;nC&#xff1a;n(┌\ulcorner┌m/2┐\urcorner┐-1)D&#xff1a;(n-1)(┌\ulcorner┌m/2┐\urcorner┐-1)1 解析 除根结点外&#xff0c;m阶B树中的每个非叶结点至…

mongodump工具安装及使用详解

MongoDB导入导出和备份的命令工具从4.4版本开始不再自动跟随数据库一起安装&#xff0c;而是需要自己手动安装。 官方网站下载链接&#xff1a;Download MongoDB Command Line Database Tools | MongoDB 将下载的压缩包通过工具上传到服务器或者虚拟机中某个路径下并解压&…

ZYNQ图像处理项目——线性神经网络识别mnist

一、线性神经网络识别mnist 线性神经网络其实也可以叫做线性分类器&#xff0c;其实就是没有激活函数的神经网络来对目标进行识别&#xff0c;像支持向量机、多元回归等都是线性的。这边我采用了线性神经网络来识别mnist数字。 我这边是看了一本讲神经网络的书籍&#xff0c;然…

分析高数值孔径物镜的聚焦特性

摘要 高数值孔径的物镜广泛用于光刻、显微等方面。 因此&#xff0c;在仿真聚焦时考虑光的矢量性质是至关重要的。VirtualLab可以支持此类透镜的光线和场追迹分析。通过场追迹分析&#xff0c;可以清楚地显示出由于矢量效应引起的非对称焦点。相机探测器和电磁场探测器可以方便…

【MySQL】Spring Boot项目基于Sharding-JDBC和MySQL主从复制实现读写分离(8千字详细教程)

目录前言一、 介绍二、 主从复制1. 原理2. 克隆从机3. 克隆从机大坑4. 远程登陆5. 主机配置6. 从机配置7. 主机&#xff1a;建立账户并授权8. 从机&#xff1a;配置需要复制的主机9. 测试10. 停止主从同步三、 读写分离1. Sharding-JDBC介绍2. 一主一从3. 一主一从读写分离3.1 …

安服-windowslinux日志分析

目录 windows日志分析 windows事件日志 日志分析工具 Linux日志分析 windows日志分析 windows事件日志 日志分析工具 Linux日志分析 rsyrslog.conf中记录了&#xff0c;这些日志文件存储的位置以及存储的内容是关于什么的日志 其中lastlog比较重要&#xff0c;记录了用户登录…

FRP之入门篇

目录 一、前言 1、概述 2、原理 3、支持功能 4、适用场景 二、环境准备 三、使用 1、安装包下载 2、服务端部署 2.1、上传安装包 2.3、启动服务端 3、客户端部署 3.1、代理服务准备 3.2、上传安装包 3.3、客户端配置 3.4、启动客户端 4、功能验证 一、前言 1、…

Redis在Windows和Linux下的安装方法(超级详细)

Redis的两种不同系统安装1. redis在Windows下的安装2. redis在Linux下的安装1. redis在Windows下的安装 下载安装包(https://github.com/MicrosoftArchive/redis/releases) 下载完后得到安装包找一个自己熟悉的路径就可以进行解压了,我放的是D盘 解压后的文件: 进入到文件夹中…

Java集合(二):Map集合与Collections工具类

目录 Map接口 Map接口的常用方法 删除方法 判断方法 查找方法 增加方法 Map常用方法&遍历操作 HashTable 字典-Dictionary,v> HashMap、HashTable和LinkedHashMap TreeMap 【2】TreeMap-存储自定义数据类型-【内部比较器】 HashMap底层源码 jdk8-源码…

央视春晚临近,主持人李思思被爆离职,知情人火速做出回应

每年的这个时候&#xff0c;中央电视台的春晚&#xff0c;都成为人们热议的话题&#xff0c;不过今年的话题却比较火爆。大众们所关注的央视春晚&#xff0c;第一是参加春晚的明星嘉宾&#xff0c;其次就是参加春晚的节目主持人。 说起央视春晚的主持人&#xff0c;最早要追溯到…

【笔试题】【day26】

文章目录第一题&#xff08;就绪队列中的进程数&#xff09;第二题&#xff08;磁盘缓冲区存在的意义&#xff09;第三题&#xff08;进程从执行态变成就绪态的原因&#xff09;第四题&#xff08;管道&#xff09;第五题&#xff08;文件打开&#xff0c;操作系统会做什么&…