Linux学习之网络编程2(socket,简单C/S模型)

news2024/11/18 23:48:42

写在前面

Linux网络编程我是看视频学的,Linux网络编程,看完这个视频大概网络编程的基础差不多就掌握了。这个系列是我看这个Linux网络编程视频写的笔记总结。


网络字节序

  • 小端法:pc本地存储,高位存高地址,低位存低地址。
  • 大端法:网络存储,高位存低地址,低位存高地址。

由此我们看到本地和网络的存储方式不一样,所以每次建立连接都要转换,下面我来介绍一些关于大端法和小端法的转换函数。

  • htonl:本地——>网络,转换的是IP
  • htons:本地——>网络,转换的是端口
  • ntohl:网络——>本地,转换的是IP
  • ntohs:网络——>本地,转换的是端口

其实这四个函数非常好记,h代表host表示本地n代表network表示网络l代表long存的IPs代表short存的是端口。(所以说学好英语还是很重要的

IP转换函数

int inet_pton(int af, const char *src, void *dst);
功能:本地字节序(string IP)——> 网络字节序。
参数:

  • af:AF_INET 或者AF_INET6
  • src:传入参数,IP地址(点分十进制)
  • dst:传出参数,转换后的网络字节序。
    返回值:
  • 成功,1
  • 异常:0,说明src指向的不是一个有效的IP地址。
  • 失败,-1

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
功能:网络字节序——>本地字节序(string IP)
参数:

  • af:AF_INET 或者AF_INET6
  • src: 网络字节序IP地址
  • dst:本地字节序(string IP)
  • sizedst的大小。
    返回值:
  • 成功,dst
  • 失败,NULL

Socket套接字

套接字概念

在通信过程中,套接字一定是 成对出现。
一个文件描述符指向一个套接字(该套接字内部由借助内核缓冲区实现读写)
1

网络通信的流程

1

  • 服务器端:
    1. 先用socket()生成一个套接字lfd用来监听
    2. bind()对第一步生成的套接字绑定地址结构(绑的是服务器的地址结构)
    3. listen()函数设置lfd的监听上限,最大是128.
    4. accept()阻塞直到有客户端请求连接。
    5. 处理请求,得到客户端的地址结构,和用于通信的套接字cfd(这个套接字是调用accept()后返回值)
    6. 成功建立连接,进行通信,处理业务逻辑。
  • 客户端:
    1. 先用socket() 生成一个套接字sfd
    2. 使用connect()请求与服务器建立连接
    3. 成功建立连接,进行通信,处理业务逻辑。

相关函数介绍

socket函数

语法:

int socket(int domain, int type, int protocol);

功能:

创建一个套接字

参数:
  • domain:AF_INETAF_INET6
  • type:数据传输协议,SOCK_STREAM(表示用流式协议,使用TCP通信传这个参数)或SOCK_DGRAM(表示用报式协议,使用UDP通信传这个参数)。(后面用本地套接字通信还会学到SOCK_LOCAL,这个后面学到再介绍)
  • protocol:默认传0,表示让系统自动根据type来选择,SOCK_STREAM的代表协议是TCPSOCK_DGRAM的是UDP
返回值:
  • 成功,新套接字所对应的文件描述符
  • 失败:-1 ,error

bind函数

语法:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:

socket绑地址结构

参数
  • sockfd:socket函数的返回值,要绑定的套接字
  • addr:传入参数,要绑定的地址结构。
  • addrlensizeof(addr) 地址结构的大小

addr类型是一个结构体,上面写的是struct sockaddr结构,实际我们创建的时候要创建struct sockaddr_in,它里面有三个成员变量。

  • sin_family:和当时创建套件字的第一个参数一样,传AF_INET
  • sin_port:绑定的端口号,只不过要转换成网络字节序
  • sin_addr.s_addr:这个是最复杂的,sin_addr本身又是一个结构体,但里面只有一个成员s_addr,所以就直接拿出来了。传的是绑定的IP地址,同样也要转换。

下面给个example,最后传的时候要类型强转一下
1

返回值:
  • 成功,0
  • 失败,-1

listen函数

语法:

int listen(int sockfd, int backlog);

功能:

设置同时与服务器建立连接的客户端数量的上限

参数:
  • sockfd:要监听的套接字
  • backlog:上限值,最大是128
返回值:
  • 成功,0
  • 失败,-1

accept函数

语法:

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

功能:

阻塞等待客户端建立连接

参数
  • sockfd:监听的套接字
  • addr:传出参数,表示建立连接的客户端的地址结构(IP+端口)
  • addrlen:传入传出参数。入:addr的大小,出:客户端addr的实际大小
返回值
  • 成功,能与服务器进行数据通信的套接字的文件描述符,即服务器用这个便可与客户端
  • 失败,-1

connect函数

语法:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:

使用客户端现有的套接字与服务器建立连接

参数:
  • sockfd:客户端自己的套接字
  • addr:服务器的地址结构
  • addrlen:服务器地址结构的长度
返回值:
  • 成功,0
  • 失败,-1

demo

说明

我们来写一个小demo,实现的功能是:客户端与服务器建立连接后,服务器可以将客户端发送的小写字母变成大写然后发送回去

服务器源代码

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<ctype.h>

#define PORT 6666

void sys_err(char * str)
{
	perror(str);
	exit(1);
}

int main()
{
	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(sfd==-1)
		sys_err("socker error");
	struct sockaddr_in addr_ser,addr_cli;
	addr_ser.sin_family=AF_INET;
	addr_ser.sin_port=htons(PORT);
	addr_ser.sin_addr.s_addr=htonl(INADDR_ANY);
	int res=bind(sfd,(struct sockaddr *)&addr_ser,sizeof addr_ser);
	if(res==-1)
		sys_err("bind error");
	res=listen(sfd,128);
	if(res==-1)
		sys_err("listen error");
	socklen_t addr_cli_len=sizeof addr_cli;
	int cfd=accept(sfd,(struct sockaddr*)&addr_cli,&addr_cli_len);
	if(res==-1)
		sys_err("accept error");
	char client_IP[1024];
	printf("client IP is %s,port is %d\n",inet_ntop(AF_INET,&addr_cli.sin_addr.s_addr,&client_IP,sizeof client_IP),ntohs(addr_cli.sin_port));
	while(1)
	{
		char buf[BUFSIZ];
		int n=read(cfd,buf,sizeof buf);
		write(STDOUT_FILENO,buf,n);
		for(int i=0;i<n;i++)
			buf[i]=toupper(buf[i]);
		write(cfd,buf,n);
	}
	return 0;
}

客户端源代码

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>

#define PORT 6666

void sys_err(char* str)
{
	perror(str);
	exit(1);
}

int main()
{
	int cfd=socket(AF_INET,SOCK_STREAM,0);
	if(cfd==-1)
		sys_err("socket error");
	struct sockaddr_in addr_ser;
	addr_ser.sin_family=AF_INET;
	addr_ser.sin_port=htons(PORT);
	inet_pton(AF_INET,"127.0.0.1",&addr_ser.sin_addr.s_addr);
	int res=connect(cfd,(struct sockaddr*)&addr_ser,sizeof addr_ser);
	if(res==-1)
		sys_err("connect error");
	while(1)
	{
		char buf[BUFSIZ];
		int n=read(STDIN_FILENO,buf,sizeof buf);
		write(cfd,buf,n);
		read(cfd,buf,n);
		write(STDOUT_FILENO,buf,n);
	}
	return 0;
}

效果展示

1

写好服务器后,可以再打开一个终端先用命令nc IP portl来测试服务器,命令里的IP是服务器的实际IP,port是服务器实际的端口


写在最后

个人亲身经验:我们学习的一系列Linux命令,一定要自己亲手去敲。不要只是看别人敲代码,不要只是停留在眼睛看,脑袋以为自己懂了,等你实际上手去敲会发现许许多多的这样那样的问题。毕竟“实践出真知”。


如果你觉得我写的题解还不错的,请各位王子公主移步到我的其他题解看看

  1. 数据结构与算法部分(还在更新中):
  • C++ STL总结 - 基于算法竞赛(强力推荐
  • 动态规划——01背包问题
  • 动态规划——完全背包问题
  • 动态规划——多重背包问题
  • 动态规划——分组背包问题
  • 动态规划——最长上升子序列(LIS)
  • 二叉树的中序遍历(三种方法)
  • 最长回文子串
  • 最短路算法——Dijkstra(C++实现)
  • 最短路算法———Bellman_Ford算法(C++实现)
  • 最短路算法———SPFA算法(C++实现)
  • 最小生成树算法———prim算法(C++实现)
  • 最小生成树算法———Kruskal算法(C++实现)
  • 染色法判断二分图(C++实现)
  1. Linux部分(还在更新中):
  • Linux学习之初识Linux
  • Linux学习之命令行基础操作
  • Linux学习之基础命令(适合小白)
  • Linux学习之权限管理和用户管理
  • Linux学习之制作静态库和动态库
  • Linux学习之makefile
  • Linux学习之系统编程1(关于读写系统函数)
  • Linux学习之系统编程2(关于进程及其相关的函数)
  • Linux学习之系统编程3(进程及wait函数)
  • Linux学习之系统编程4(进程间通信)
  • Linux学习之系统编程5(信号)
  • Linux学习之系统编程6(线程)
  • Linux学习之系统编程7(线程同步/互斥锁/信号量/条件变量)
  • Linux学习之网络编程(纯理论)

✨🎉总结

“种一颗树最好的是十年前,其次就是现在”
所以,
“让我们一起努力吧,去奔赴更高更远的山海”
在这里插入图片描述
如果有错误❌,欢迎指正哟😋

🎉如果觉得收获满满,可以动动小手,点点赞👍,支持一下哟🎉

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

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

相关文章

AI技术已经发现了一种新材料,可以在电池制造中减少对锂的需求

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Docker 安装:在linux系统CentOS7 版本 安装Docker

目录 一&#xff0c;Docker介绍&#xff1a; 1.1Docker是什么&#xff1f; 1.2Docker组成 二&#xff0c;Docker安装&#xff1a; 三&#xff0c;Docker基本使用 3.1服务 3.2镜像 3.3容器 &#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&am…

UniApp调试支付宝沙箱(安卓)

先看下这里完整的交互的图&#xff1a;小程序文档 - 支付宝文档中心 一、打包 不管怎样&#xff0c;先打个包先。可以直接使用云端证书、云端打包&#xff0c;只需要指定包名即可。 二、在支付宝开放平台创建应用 这个参考官方的过程就可以了&#xff0c;只要有刚才打的包&…

【REST2SQL】08 日志重构增加输出到文件log.txt

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 原来…

解决:ModuleNotFoundError: No module named ‘pymysql’

解决&#xff1a;ModuleNotFoundError: No module named ‘pymysql’ 文章目录 解决&#xff1a;ModuleNotFoundError: No module named pymysql背景报错问题报错翻译报错位置代码报错原因解决方法方法一&#xff0c;直接安装方法二&#xff0c;手动下载安装方法三&#xff0c;…

php多小区智慧物业管理系统源码带文字安装教程

多小区智慧物业管理系统源码带文字安装教程 运行环境 服务器宝塔面板 PHP 7.0 Mysql 5.5及以上版本 Linux Centos7以上 统计分析以小区为单位&#xff0c;统计如下数据&#xff1a;小区总栋数、小区总户数、小区总人数、 小区租户数量、小区每月收费金额统计、小区车位统计、小…

C#,入门教程(14)——字符串与其他数据类型的转换

上一篇&#xff1a; C#&#xff0c;入门教程(13)——字符&#xff08;char&#xff09;及字符串&#xff08;string&#xff09;的基础知识https://blog.csdn.net/beijinghorn/article/details/123928151 数据只有可视化才能更好地体现其价值&#xff0c;因而 string 与 image…

【软件测试】学习笔记-微服务模式下API测试

这篇文章探讨当下最热门的技术领域的API测试&#xff0c;即微服务模式下的API测试。微服务架构下&#xff0c;API测试的最大挑战来自于庞大的测试用例数量&#xff0c;以及微服务之间的相互耦合。这篇文章探讨这两个问题的本质&#xff0c;以及如何基于消费者契约的方法来应对这…

SQL-数据类型

目录 DDL-表操作-数据类型 数值类型 字符串类型 举例&#xff1a; 案例&#xff1a; 日期时间类型 案例 表操作-案例 &#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &a…

【常用的简单功能及算法】拦截器 加盐算法 深克隆 时间日期格式化 加盐算法 sql分页算法 验证码

1.实现拦截器 Interceptor (以登录拦截器为例) 1.1 写一个登录拦截器普通类 实现HandlerInterceptor接口重写preHandle方法 //检验登录状态拦截器 //实现接口HandlerInterceptor 重写方法preHandle public class LoginInterceptor implements HandlerInterceptor {/** 该方…

网络安全保险发展起始阶段的挑战及应对措施

文章目录 前言一、网络安全保险的有序发展二、当前我国网络安全保险发展的初期态势&#xff08;一&#xff09;网络安全风险类型&#xff08;二&#xff09;网络安全保险的作用&#xff08;三&#xff09;与外国网络安全保费的规模对比 三、我国网络安全保险发展初期面临的挑战…

一天一个设计模式---适配器模式

概念 适配器模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的接口之间进行协同工作&#xff0c;使得原本由于接口不匹配而无法合作的类能够一起工作。 具体内容 适配器模式主要包括以下几个要素&#xff1a; 目标接…

yolov8 瑞芯微 RKNN 的 C++部署,部署工程难度小、模型推理速度快

之前写过两次yolov8目标检测部署&#xff0c;后续继续思考&#xff0c;针对部署还有优化空间&#xff0c;本示例的部署方式优化了部署难度&#xff0c;加快了模型推理速度&#xff08;略微增加了后处理的时耗&#xff09;。 特别说明&#xff1a;如有侵权告知删除&#xff0c;…

半Happy的一天

终于差不多将SWMM模型与LisFlood模型耦合运转起来了 MDL的雏型也出来了&#xff0c;注册了模型方法和参数&#xff0c;差一个方法参数 晚上和师兄聊了聊未来规划&#xff0c;回顾了这半年研究生生涯的“拍烂”生活&#xff08;其实也没特别摆烂&#xff0c;还是学了不少东西&…

服务器数据传输安全如何保障?保障意义是什么?

数据安全&#xff0c;是指通过采取必要措施确保数据处于有效保护和合法利用的状态&#xff0c;以及具备保障持续安全状态的能力。数据安全应保证数据生产、存储、传输、访问、使用、销毁、公开等全过程的安全&#xff0c;并保证数据处理过程的保密性、完整性、可用性。无论是互…

SpringBoot知识02

1、快速生成mapper和service &#xff08;自动生成简单的单表sql&#xff09; 2、springboot配置swagger&#xff08;路径不用加/api&#xff09; &#xff08;1&#xff09;主pom导包&#xff08;子pom要引用&#xff0c;可选依赖&#xff09; <!-- swagger3…

git提交记录全部删除

目录 问题描述 解决方案 结果 问题描述 新复制的项目具有特比多的提交记录我想给他清除&#xff0c;因为不清楚过多历史也就导致包特别大下载和提交等方面都不是很快 解决方案 查看代码clone网址&#xff1b; 打开远程仓库&#xff0c;选择要去除历史记代码分支&#xff08…

C2855 命令行选项“/Zc:referenceBinding“与预编译头不一致和C2855 命令行选项“/Zc:__cplusplus“与预编译头不一致

在VS2019和Qt5.12.12环境下&#xff0c;笔记本上编译这个工程没有问题&#xff0c;把工程拷贝到台式机上&#xff0c;一样的配置&#xff0c;但是报如下错误&#xff1a; 打开项目的命令行配置如下&#xff1a; 解决办法&#xff1a;在编译选项"/Zc:referenceBinding"…

大模型LLM Agent在 Text2SQL 应用上的实践

1.前言 在上篇文章中「如何通过Prompt优化Text2SQL的效果」介绍了基于Prompt Engineering来优化Text2SQL效果的实践&#xff0c;除此之外我们还可以使用Agent来优化大模型应用的效果。 本文将从以下4个方面探讨通过AI Agent来优化LLM的Text2SQL转换效果。 1 Agent概述2 Lang…

内网穿透的应用-使用Docker部署开源建站工具—Halo,并实现个人博客公网访问

文章目录 1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤&#xff1a;1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 本篇文章介绍如何在CentOS下使用D…