《TCP/IP网络编程》第3,4章学习记录

news2024/11/26 15:46:08

基础知识: 

struct sockaddr_in
{
	sa_family_t	sin_family;	//地址族(Address Family)
	uint16_t	sin_port;	//16位TCP/UDP端口号
	struct in_addr	sin_addr;	//32位IP地址
	char		sin_zero[8];	//不使用
}

sa_family_t包括:
(1)AF_INET,IPv4网络协议使用的地址族
(2)AF_INET6,IPv6网络协议使用的地址族
(3)AF_LOCAL,本地通信中采用的UNIX协议的地址族
...etc...

struct in_addr{
	in_addr_t	s_addr;		//32位IPV4地址
}

in_addr_t:IP地址,声明为uint32_t

struct sockaddr
{
	sa_family_t	sin_family;	//地址族(Address Family)
	char		sa_data[14];	//地址信息
}
14=2+4+8字节

sin_port,sin_addr均以网络字节序保存。

在0x20号开始的地址中保存4字节int型数0x12345678.
大端序:高位字节放在低位地址。
0x20:0x12
0x21:0x34
0x22:0x56
0x23:0x78
小端序:高位字节放在高位地址。
0x20:0x78
0x21:0x56
0x22:0x34
0x23:0x12

目前主流的Intel系列CPU以小端序方式保存数据。

网络字节序:大端序。

htons
ntohs
htonl
ntohl
h:host:主机
n:network:网络
s:short:linux中是2个字节
l:long:linux中是4个字节


字节序相关代码:

主机字节序转网络字节序:

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc,char *argv[])
{
	unsigned short host_port=0x1234;
	unsigned short net_port;
	unsigned long host_addr=0x12345678;
	unsigned long net_addr;

	net_port=htons(host_port);
	net_addr=htonl(host_addr);

	printf("Host ordered port:%#x \n",host_port);
	printf("Network ordered port:%#x \n",net_port);
	printf("Host ordered address:%#lx \n",host_addr);
	printf("Network ordered address:%#lx \n",net_addr);

	return 0;
}

结果:

 函数:

点分10进制转32位大端序整型数

in_addr_t inet_addr(const char *string);
成功时返回32位大端序整数型值,失败时返回INADDR_NONE;

样例:

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	char *addr1="1.2.3.4";
	char *addr2="1.2.3.256";

	unsigned long conv_addr=inet_addr(addr1);
	if(conv_addr ==INADDR_NONE)
		printf("Error occured!\n");
	else
		printf("Network ordered integer addr: %#lx \n",conv_addr);
	conv_addr=inet_addr(addr2);
        if(conv_addr ==INADDR_NONE)
                printf("Error occured!\n");
        else
                printf("Network ordered integer addr: %#lx \n",conv_addr);
	return 0;
}

结果: 

 

函数:

点分10进制字符串转32位大端序整型数,存储在struct in_addr中

int inet_aton(const char * string,struct in_addr * addr);
成功时返回1,失败时返回0.

样例:

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>

void error_handling(char *message);

int main(int argc ,char *argv[])
{
	char *addr="127.232.124.79";
	struct sockaddr_in addr_inet;
	if(!inet_aton(addr,&addr_inet.sin_addr))
		error_handling("Conversion error");
	else
		printf("Network ordered integer addr: %#x \n",addr_inet.sin_addr.s_addr);
	return 0;
}

void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

结果:

 Linux下:

迭代服务器端:

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

#define BUF_SIZE 1024
void error_handling(char * message);

int main(int argc,char * argv[])
{
	int serv_sock,clnt_sock;
	char message[BUF_SIZE];
	int str_len,i;

	struct sockaddr_in serv_addr,clnt_addr;
	socklen_t clnt_adr_sz;

	if(argc!=2)
	{
		printf("Usage: %s <port>\n",argv[0]);
		exit(1);
	}

	serv_sock=socket(PF_INET,SOCK_STREAM,0);
	if(serv_sock==-1)
		error_handling("socker() error");
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_addr.sin_port=htons(atoi(argv[1]));

	if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
		error_handling("bind() error");
	if(listen(serv_sock,5)==-1)
		error_handling("listen() error");
	clnt_adr_sz=sizeof(clnt_addr);
	for(int i=0;i<5;i++)
	{
		clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_adr_sz);
		if(clnt_sock==-1)
			error_handling("accept() error");
		else
			printf("Connected client %d\n",i+1);
		while((str_len=read(clnt_sock,message,BUF_SIZE))!=0)
			write(clnt_sock,message,str_len);
		close(clnt_sock);
	}
	close(serv_sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

回声客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024

void error_handling(char * message);

int main(int argc,char *argv[])
{
	int sock;
	struct sockaddr_in serv_addr;
	char message[BUF_SIZE];
	int str_len;
	if(argc!=3)
	{
		printf("Usage : %s <IP> <port>\n",argv[0]);
		exit(1);
	}

	sock=socket(PF_INET,SOCK_STREAM,0);
	if(sock == -1)
		error_handling("socket() error");
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
	serv_addr.sin_port=htons(atoi(argv[2]));

	if(connect(sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr))==-1)
		error_handling("connect() error!");
	else 
		puts("Connected......");
	while(1)
	{
		fputs("Input message(Q to quit):",stdout);
		fgets(message,BUF_SIZE,stdin);

		if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
			break;
		write(sock,message,strlen(message));
		str_len=read(sock,message,BUF_SIZE-1);
		message[str_len]=0;
		printf("Message from server : %s \n",message);
	}

	close(sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

实现效果:

服务器端等待队列大小为5,意思是可以有5个客户端发起connect连接,它们的连接请求会被注册到服务器端等待队列,但只有第一个客户端会与服务器通信,后面的必须等待上一个客户端结束通信才可建立连接。

 

 但因为TCP不存在数据边界

所以可能

write了好几次,却一次到达

read了好几次,却一次把数据都读了出来

也可能write了一次,却几次才到达

read了一次,却几次才把数据读完

(这是上面的程序存在的问题)

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

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

相关文章

【Linux】分布式监控 Zabbix

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Zabbix 介绍zabbix 概述Zabbix 监控原理Zabbix 6.0 新特性Zabbix 6.0 功能组件 Zabbix 6.0 部署Zabbix 添加客户端主机Zabbix 自定义监控内容Zabbix 自动发现与自动…

2.1、修改Gitea上传附件大小限制

目录 1. 修改Gitea配置2. 重启服务3. 使用 之前在Gitea上传附件时&#xff0c;显示大小超过3MB&#xff0c;不能符合我的使用场景。记录一下修改这个限制的配置。 1. 修改Gitea配置 默认在安装路径的custom/conf/app.ini文件中&#xff1a; 添加参数 [repository.upload] ; 是…

linux下cuda的安装

linux下cuda的安装 安装cuda11.1和pytorch1.8安装显卡驱动第一个报错第二个报错第三个错误屏幕不显示问题解决方案 安装cuda11.1 安装cuda11.1和pytorch1.8 通过上表可以发现&#xff0c;如果要使用CUDA11.1&#xff0c;那么需要将显卡的驱动更新至455.23或以上&#xff08;Lin…

SpringBoot2+Vue2实战(十六)vue集成视频播放组件

修改文件上传大小限制 servlet:multipart:max-file-size: 100MBmax-request-size: 100MB Video.vue <template><div style"padding: 10px"><el-card><div v-for"item in videos" :key"item.id"style"margin: 10px 0…

走进Linux世界【二、VM与Linux安装】

第二章 VM与Linux安装 1、安装VMware ​ 这里安装Vm主要是为了安装Linux系统&#xff0c;除了相对云服务器&#xff0c;比较大众化的操作&#xff0c;当然更多的是熟悉Linux操作 1、Windows安装 ​ (1) 下载链接&#xff0c;目前版本上下载VM15的版本即可https://www.vmwar…

JavaScript ES6实现继承

1 对象的方法补充 2 原型继承关系图 3 class方式定义类 4 extends实现继承 5 extends实现继承 6 多态概念的理 function 创建的名称如果开头是大写的&#xff0c;那这个创建的不是函数&#xff0c;是创建了类。 ES6-class类中的内容 <!DOCTYPE html> <html lang&…

ChatGPT助力校招----面试问题分享(十一)

1 ChatGPT每日一题&#xff1a;PCB布线&#xff0c;高速信号线走直角的后果 问题&#xff1a;PCB布线&#xff0c;高速信号线走直角的后果 ChatGPT&#xff1a;对于高速信号线来说&#xff0c;最好避免使用直角布线。直角布线会引入反射和信号损耗&#xff0c;从而导致信号完…

IP网络基础

文章目录 数据通信基础数据流方向&#xff08;工作模式&#xff09;网络和Internet简介网络&#xff1a;互联网&#xff1a;总结&#xff1a; 协议和标准标准化组织标准化组织——IETF标准的种类 IP网络基本架构 lP网络在现代社会中有着越来越重要的地位。本课程将介绍数据通信…

详解c++---c++11(上)

目录标题 {}初始化decltype和autonullptr范围forfinal什么是左值和右值左值引用和右值引用右值引用的意义右值引用的使用const右值引用万能引用默认移动构造和移动赋值 {}初始化 在c98中允许使用{}对数组或者结构体元素进行统一的列表初始值设定&#xff0c;比如说下面有个结构…

使用USB转TTL线连接树莓派4B

一般我们刷完树莓派系统后&#xff0c;都是通过连接鼠标键盘及显示器来进行操作&#xff0c;当我们开启SSH功能后我们才可以通过ssh客户端进行远程访问&#xff0c;那么是否有更方便的方式进行连接&#xff0c;并且不需连接外部设备进行操作呢&#xff1f; 串口通信 当然可以…

python3+requests+unittest实战系列【一】

1.环境准备 python3 pycharm编辑器 2.框架目录展示 &#xff08;该套代码只是简单入门&#xff0c;有兴趣的可以不断后期完善&#xff09; &#xff08;1&#xff09;run.py主运行文件&#xff0c;运行之后可以生成相应的测试报告&#xff0c;并以邮件形式发送&#xff1b;…

探索现代设备管理系统的功能和优势

在现代工业环境中&#xff0c;设备管理对于企业的生产效率和可靠性至关重要。随着科技的不断发展&#xff0c;现代设备管理系统为企业提供了更多的优势和功能&#xff0c;以帮助企业实现设备全生命周期管理和优化运营。本文将探索现代设备管理系统的优势和功能&#xff0c;以帮…

PicGo搭建Gitee图床

文章目录 1、创建Gitee仓库2. 填写仓库信息3、生成私人令牌3.1、点击个人设置3.2、点击私人令牌3.3、生成新令牌3.4、密码验证3.5、记录个人令牌 4、PicGo配置4.1、插件设置&#xff0c;安装gitee插件4.2、PicGo图床配置为gitee并设置详细信息 5、特殊问题5.1、上传失败原因15.…

Vue3 +Echarts5 可视化大屏——屏幕适配

项目基于Vue3 Echarts5 开发&#xff0c;屏幕适配是使用 scale 方案 Echarts组件按需引入&#xff0c;减少打包体积 地图组件封装&#xff08;全国&省份地图按需加载&#xff09; 效果图&#xff1a; 屏幕适配 大屏适配常用的方案有 rem vw/vh 和 scale 。 rem vw/vh …

C++之虚函数和纯虚函数多态调用区别(一百五十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

中值滤波的运用

需求&#xff1a; c#、WPF开发&#xff0c;在界面上画不规则的图形区域&#xff0c;并提取区域内的point 实现方式&#xff1a; 1. 用 InkCanvas控件作为画布&#xff0c;用path画不规则图形 2. 将InkCanvas控件内的内容保存为jpg图片 3. 通过判断区域的颜色&#xff0c;从而得…

离散化模板(附 区间和 解决方法)

目录 用于解决的问题类型&#xff1a; 作用&#xff1a; 使用到的函数&#xff1a; 常用模板&#xff1a; 例题引入&#xff1a; 题目&#xff1a; 解题思路&#xff1a; 代码详解&#xff1a; 用于解决的问题类型&#xff1a; 对于值域比较大&#xff0c;但个数比较少…

python爬虫之playWright解密传参

参考文章&#xff1a; Python和js实现逆向之加密参数破解_js btoa python_biyezuopinvip的博客-CSDN博客 JS逆向——借助playwright实现逆向_lishuangbo0123的博客-CSDN博客 简单方便的 JavaScript 逆向辅助模拟方法_token 自己整理的代码 from playwright.sync_api impor…

数组、指针练习题及解析(含笔试题目讲解)(二)

接上文&#xff0c;我们继续笔试题目讲解。 目录 笔试题3 笔试题4 笔试题5 笔试题6 笔试题7 面试题8 总结 笔试题3 int main() {int a[4] { 1, 2, 3, 4 };int *ptr1 (int *)(&a 1);int *ptr2 (int *)((int)a 1);printf( "%x,%x", ptr1[-1], *ptr2);…

postman 携带时间戳及md5加密预处理

// 获取全局变量 uid postman.getGlobalVariable(“uid”) sid postman.getGlobalVariable(“sid”) //设置当前时间戳 postman.setGlobalVariable(“time”,Math.round(new Date().getTime())); time postman.getGlobalVariable(‘time’) //设置KEY_WORD为全局变量 post…