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;
}

输出结果

相关推荐
Zfox_32 分钟前
【Linux】进程信号全攻略(二)
linux·运维·c语言·c++
速盾cdn32 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
安於宿命37 分钟前
【Linux】简易版shell
linux·运维·服务器
黄小耶@1 小时前
linux常见命令
linux·运维·服务器
叫我龙翔1 小时前
【计网】实现reactor反应堆模型 --- 框架搭建
linux·运维·网络
古驿幽情1 小时前
CentOS AppStream 8 手动更新 yum源
linux·运维·centos·yum
BillKu1 小时前
Linux(CentOS)安装 Nginx
linux·运维·nginx·centos
BillKu1 小时前
Linux(CentOS)yum update -y 事故
linux·运维·centos
a266378961 小时前
解决yum命令报错“Could not resolve host: mirrorlist.centos.org
linux·运维·centos
不爱学习的YY酱2 小时前
【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】试卷(4)
网络·计算机网络