Linux网络编程一(协议、TCP协议、UDP、socket编程、TCP服务器端及客户端)

文章目录

第二次更新,自己再重新梳理一遍...

协议

协议:指一组规则,数据传输 和数据解释的规则。

1、分层模型结构

1、OSI七层模型:物、数、网、传、会、表、应

2、TCP/IP 4层模型:应、传、网、网(链路层)、
用户应用层 http(超文本传输协议,以明文方式发送内容,没有任何加密)、https(提供网络连接的加密,客服端输入的数据放入盒子中加锁后由服务器端接收后解锁)、ftp、nfs、ssh(一种加密传输协议,通过命令行界面远程登录和操作计算机)、telnet
内核传输层 TCP、UDP 捆绑端口号 ③ 网络层 IP、ICMP 传输ip地址 ④链路层 以太网帧协议、ARP

2、网络应用程序设计模式

1、c/s模型

client-server(客户端服务器模型):网游

优点:缓存大量数据、协议选择灵活、速度快、

缺点:安全性低、跨平台难、开发工作量大

2、 b/s模型

browser-server(浏览器服务器模型): 百度网站

优点:安全性高、跨平台、开发工作量较小

缺点:不能缓存大量数据、严格遵守http协议

网络传输流程:数据没有封装之前,是不能再网络中传递的。数据->应用层->传输层->网络层->链路层,以此进入网络环境。

3、ARP协议

根据IP地址获取mac地址,mac地址指的是以太网或者物理地址,例如:比如 00:1B:44:11:3A:B7。

以太网帧协议:根据mac地址,完成数据包传输。

4、IP协议

1、版本:IPv4、IPv6 4位。

2、TTL:下一跳,设置数据包在路由节点中的跳转上限。每经过一个路由节点,该值减1,减为0的路由,有义务将该数据包丢弃。

3、源IP:32位对应4字节,32位二进制代码,每个位置8位,如:192.168.1.108,点分十进制 IP地址(string)。

4、目的IP:32位对应4字节,Ip地址共4字节,每个字段上限255。

5、IP地址:可以在网络环境中,唯一标识一台主机(特定设备)。(家庭住址)

6、端口号:可以在网络的一台主机上,唯一标识一个进程(特定应用程序)。

7、ip地址+端口号:可以在网络环境中,唯一标识一个进程。准确定位网络上的特定设备 上的特定应用程序

5、UDP协议

用户数据报协议 (User Datagram Protocol),IP负责把数据包送到正确的计算机中,UDP负责把数据包送到正确的程序,UDP不提供数据修复和重发的机制,且无法知道数据包是否送达,数据的确实不重要但是快!如:适用于游戏。

端口:操作系统与外部进行交互使用。

①公认端口:1~1023,用于一些系统内置或知名程序的预留使用,如SSH服务的22端口

②注册端口:1024~49151,随意使用,用于松散的绑定一些程序/服务。

③动态端口:49152~65535,临时使用 不会固定绑定程序,用于程序对外进行网络链接时 (多用于出口)。
16位源端口号,2^16 = 65536 。16位:目的端口号,如:微信端口号是8080,则送入到微信程序中。

6、TCP协议

TCP(Transmission Control Protocol,传输控制协议 ),它位于网络协议栈的传输层,负责在通信的两个应用程序之间提供可靠的、面向连接的数据传输服务。

数据包有序号,TCP发送数据包时,需要接收方收到后给发送方发确认码。TCP可以处理乱序和丢失数据包重发,根据拥挤情况,自动调整传输率。最大的缺点是数据量大,要发确认码,浪费传输时间。

16位源端口号 2^16 = 65536;16位目的端口号;32序号;32确认序号; 6个标志位;16位窗口大小

Socket编程

1、网络套接字(socket)

*网络套接字(socket): Linux特殊文件类型(管道、套接字、字符设备、块设备)。

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

套接字(socket)通信原理图如下:

2、网络字节序

网络字节序:通信时需要进行网络字节序和主机字节序的转换

小端法(pc本地存储),高位存高地址, 低位存低地址,int a = 0x12345678

大端法(网络存储),高位存低地址, 低位存高地址

htonl:本地转到网络(IP)。费劲!看下面的IP地址转换

htons:本地转网络(port端口)

ntohl:网络转本地(IP)

ntohs:网络转本地(Port)

3、IP地址转换

IP地址转换

int inet_pton(int af, const char *src, void *dst);将本地字节序(string IP)--->网络字节序,客户端连接时使用。

const char* inet_ntop(int af, const void *src, char *dst, socklen_t size);

网络字节序--->本地字节序(string IP),从网络中得到,accept传出时使用。

sockaddr地址结构(过时)

IP +port:在网络环境中唯一标识一个进程

struct sockaddr_in addr。作用:用来捆绑IP、端口号
sockaddr_in结构体成员

1、addr.sin_family = AF_INET/ AF_INET6/ AF_UNIX

2、addr.sin_port = htons(9527)

3、addr.sin_addr.s_addr = dst

int dst;inet_pton(AF_INET, "192.157.22.45", (void *)&dst)

3、addr.sin_addr.s_addr = htonl(INADDR_ANY)

取出当前系统中有效的任意IP地址,二进制类型。INADDR_ANY这个宏表示本地的任意的有效IP地址

4、一系列函数

socket函数 :创建一个 套接字伪文件

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

bind函数 :给socket绑定一个 地址结构(IP+port)

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

listen函数 :设置同时与服务器建立连接的上限数(同时进行三次握手的客户端数量)

int listen(int sockfd, int backlog);

accept函数 :阻塞等待客户端建立连接。成功即返回一个与客户端成功连接的socket新文件描述符

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

caonnect函数 :使用现有的 socket 与服务器建立连接

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

5、TCP通信流程分析

server服务器端

1、socket() 创建socket

2、bind()绑定服务器地址结构

3、listen()设置监听上限

4、accept() 阻塞监听客户端连接

5、read(fd)读socket获取客户端数据

6、小---大写 toupper()

7、write(fd)

8、close()
client客户端

使用 nc IP地址 端口号,可以直接测试服务器端

1、socket() 创建socket

2、connect()与服务器建立连接

3、write()写数据到 socket

4、read()读转换后的数据

5、显示读取结果

6、close()

server服务器端代码

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 9527

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

int main(int argc, char* argv[])
{
	int lfd = 0;									//新套接字所对应的文件描述符
	int cfd = 0;									//建立连接通信的文件描述符
	int ret;
	char buf[BUFSIZ], client_IP[1024];			    //BUFSIZ 宏值默认为4096

	struct sockaddr_in serv_addr;					//服务端地址
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//这个宏表示本地的任意的有效IP地址

	struct sockaddr_in clit_addr;					//客户端地址
	socklen_t clit_addr_len;

	lfd = socket(AF_INET, SOCK_STREAM, 0);		    //创建套接字 IPV4 TCP协议
	if (lfd == -1) {
		sys_err("socket error");
	}

	//给socket绑定一个 地址结构(IP+port)
	bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

	listen(lfd, 128);

	//阻塞等待客户端建立连接。成功即返回一个与客户端成功连接的socket新文件描述符
	clit_addr_len = sizeof(clit_addr);
	cfd = accept(lfd, (struct sockaddr*)&clit_addr, &clit_addr_len);
	if (cfd == -1) {
		sys_err("accept error");
	}
	//addr: 传出参数。成功与服务器建立连接的那个客户端的地址结构(IP+port) 需要网络转本地
	printf("client ip:%s  port:%d\n", inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, client_IP, sizeof(client_IP)),
		ntohs(clit_addr.sin_port));

	while (1) {
		ret = read(cfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, ret);					//打印输出小写
		for (int i = 0; i < ret; i++) {
			buf[i] = toupper(buf[i]);					//小写转大写
		}

		write(cfd, buf, ret);							//写回客户端
	}

	close(lfd);
	close(cfd);

	return 0;
}

client客户端代码

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>

#define SERV_PORT 9527

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

int main(int argc, char* argv[])
{
	int cfd;
	int conter = 10;
	char buf[BUFSIZ];

	struct sockaddr_in serv_addr;				//服务器地址结构
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);
	inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);
	//serv_addr.sin_addr.s_addr = 				//需要写服务器IP

	cfd = socket(AF_INET, SOCK_STREAM, 0);
	if (cfd == -1) {
		sys_err("socket error");
	}

	//使用现有的 socket 与服务器建立连接
	int ret = connect(cfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
	if (ret == -1) {
		sys_err("connect error");
	}

	while (--conter) {
		write(cfd, "hello\n", 6);
		sleep(1);
		ret = read(cfd, buf, sizeof(buf));
		write(STDOUT_FILENO, buf, ret);
	}

	close(cfd);

	return 0;
}

输出结果

相关推荐
大聪明-PLUS17 小时前
关于新的 Linux 内核接口 gpio uapi 的说明
linux·嵌入式·arm·smarc
玉树临风江流儿17 小时前
Linux驱动开发总结速记
linux·运维·驱动开发
cccyi717 小时前
Linux 进程信号机制详解
linux·signal·volatile
Hello.Reader18 小时前
Flink 受管状态的自定义序列化原理、实践与可演进设计
java·网络·flink
gd632137418 小时前
银河麒麟 aarch64 linux 里面的 qt 怎么安装kit
linux·服务器·qt
A-花开堪折19 小时前
Qemu 嵌入式Linux驱动开发
linux·运维·驱动开发
磊灬泽19 小时前
【Linux驱动开发】PWM子系统-servo
linux·运维·算法
郝学胜-神的一滴20 小时前
Linux系统函数stat和lstat详解
linux·运维·服务器·开发语言·c++·程序人生·软件工程
Mr.亮先生20 小时前
常用、高效、实用的 Linux 服务器监控与运维工具清单
linux·运维·服务器
poemyang20 小时前
单线程如何撑起百万连接?I/O多路复用:现代网络架构的基石
linux·rpc·i/o 模式