Linux11:Linux网络编程(虚拟机网络连接,UDP,TCP/IP协议,IP地址,端口号,字节序,socket系统调用,套接字编程)

Linux网络编程(虚拟机网络连接,UDP,TCP/IP协议,IP地址,端口号,字节序,socket系统调用,套接字编程)

1.网络编程相关知识:

1.1.虚拟机网络连接:

桥接:桥接到物理机网卡上,虚拟机、物理机、外网都可以进行相互访问

仅主机:虚拟机仅和物理机进行通信

NAT:和桥接对比,外网不能访问虚拟机

1.2.常用命令:

ifconfig命令:
查看以及配置linux下的网络
#ifconfig //查看网络配置
#ifconfig ens33 192.168.15.2 //设置ens33网络
vim /etc/network/interfaces
#ifconfig ens33 up/down
打开或者关闭网卡

ping命令
测试当前网络和另一个IP地址是否网络连通
ping xxxxip地址 //一直阻塞终端
ping -c%d xxxip地址 //ping %d 次
重启网络
service networking restart

1.3.关于网络:

TCP/IP协议架构与OSI七层模型:
在这里插入图片描述

TCP/IP协议:
传输控制/网际协议(Transfer Control Protocol/Internet Protocol) 又称作网络通讯协议
是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成

2.传输层:

2.1.通信协议:

TCP:
利用套接字进行通信
TCP协议编程框架:
在这里插入图片描述

特点:

传输安全可靠,传输过程有三次握手,实时性差
密码验证等
基于连接的通信(可靠通信):
通信前两个进程先握手建立连接,数据不会丢失

TCP三次握手建立连接:
在这里插入图片描述
UDP:

利用套接字进行通信
特点:

传输不可靠,实时性强
用于音频,视频传输

UDP编程框架:
在这里插入图片描述

基于无连接通信(不可靠通信)
通信前无连接,数据可能丢失
UDP

2.2.IP地址:

组成:

网络ID:
指定 了主机所属的网络
主机ID:
标识了位于该网络中的主机

分类:

ipv4: 包含32位
0.0.0.0~255.255.255.255
点分十进制形式,将地址的4个字节写成以个十进制数字
ipv6:128位

区分:
子网掩码
划分:网络ID全为1,主机ID全为0
表示:
192.168.1.0/24
可分配的因特网地址为 192.168.1.1---------192.168.1.254
主机ID全为0的用来标识网络本身
主机ID全为1标识子网广播地址
255.255.255.0

特殊IP:

127.0.0.1:回环地址,分配给主机名localhost
127.0.0.0/8中的所有地址均可分配为回环地址,通常使用127.0.0.0;
INADDR_ANY: ipv4通配地址,常用于将socket绑定到多宿主机的应用程序

2.3.IP转换函数:

ipv4:
原型:

int inet_aton(const char *cp, struct in_addr *inp);
//点分十进制IP-->网络字节的32位二进制数值
int inet_aton(const char *cp, struct in_addr *inp);
//点分十进制IP-->网络字节的32位二进制数值
int inet_aton(const char *cp, struct in_addr *inp);
//点分十进制IP-->网络字节的32位二进制数值
char *inet_ntoa(struct in_addr in);
//32-->点分十进制
in_addr_t inet_addr(const char *cp);
//点分十进制IP-->网络字节的32位二进制数值并返回

所属头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

参数:

cp:存放点分十进制IP地址字符串
inp:传出参数,保存32位二进制数值
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};

ipv4和ipv6:
原型:

int inet_pton(int af, const char *src, void *dst);
//类比inet_aton
const char *inet_ntop(int af, const void *src,char *dst, socklen_t cnt);

所属头文件:
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
参数:

af:AF_INET:表示为ipv4
AF_INET6:表示为ipv6
cnt为转换后的长度(字符串的长度)

2.3:端口号:

一个是16位无符号整形,0-65535
区分一台主机接收到的数据包应该转交给哪个进程来进行处理:
在这里插入图片描述

1到1023(1到255之间为众所周知端口,256~1023端口通常由UNIX系统占用)
注册端口:1024~49150; 可以使用
动态或私有端口:49151~65535
套接字和端口:
在这里插入图片描述
2.4:地址名字转化:

原型:

struct hostent* gethostbyname(const char* hostname);
//将域名(www.baidu.com)或主机名转换为 IP 地址
struct hostent* gethostbyaddr(const char* addr, size_t len, int family);
//将 IP 地址转换为域名或主机名

所属头文件:
#include <netdb.h>
参数:

hostname:指向存放域名或主机名的字符串
struct hostent
{
char *h_name; /正式主机名/
char **h_aliases; /主机别名/
int h_addrtype; /主机 IP 地址类型 IPv4 为 AF_INET/
int h_length; /主机 IP 地址字节长度,对于 IPv4 是 4 字节,即 32 位/
char **h_addr_list; /主机的 IP 地址/
}
addr :IP 地址,通过函数 inet_aton()转换
len : IP 地址的长度, AF_INET 为 4。
family 可用 AF_INET:Ipv4 或 AF_INET6: Ipv6

2.5:字节序:

不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO):

小端序(little-endian)
存储数据是先存最低有效位
低序字节存储在低地址,Intel、AMD等采用的是这种方式
大端序(big-endian)
存储数据是先存最高有效位
高序字节存储在低地址,ARM、Motorola等所采用
网络中传输的数据必须按网络字节序,即大端字节序
当应用进程将整数送入socket前,需要转化成网络字节序;当应用进程从socket取出整数后,要转化成主机节序

转化:

 uint32_t htonl(uint32_t hostlong);
 //本函数将一个32位数从主机字节顺序转换成无符号长整型网络字节顺序
  //host  ----> network   long
  uint16_t htons(uint16_t hostshort);
  //将一个无符号短整型的主机数值转换为网络字节顺序
   //short
  uint32_t ntohl(uint32_t netlong);
  //将一个无符号长整形数从网络字节顺序转换为主机字节顺序。
  uint16_t ntohs(uint16_t netshort);
  //将一个16位数由网络字节顺序转换为主机字节顺序。

2.5:socket系统调用:

 socket()
 系统调用创建一个新的socket
 bind()
 系统调用将一个socket绑定到一个地址上,统称,服务器需要使用这个调用来将其socket绑定到一个总所周知的地址上使得客户端能够定位到该socket上
 listen()
 系统调用允许一个流socket接收来自其他socket的介接入链接
 accept()
 系统调用在一个监听流socket上接受来自一个队等应用程序的连接,并可选的返回对等socket的地址
 connect()
 系统调用建立与另一个socket之间的连接

3.套接字编程:

服务器操作流程:
3.1:什么是套接字:

网络接口函数集,打开的网络,对比文件操作中的文件描述符,socket有描述符、IP地址、端口号等
分类:

流式套接字(SOCK_STREAM):
提供可靠的、面向连接的通信流,保证数据传输的正确性和顺序性—TCP
数据报(SOCK_DGRAM):
无连接的服务,独立报文传输,无序,不保证是可靠、无差错的----UDP
原始套接字(SOCK_RAW):很少用,对底层协议直接访问,用于一些协议开发

3.2:创建socket,用socket函数:

原型:

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

头文件:
#include <sys/socket.h>
参数:

domain: 网域
AF_INET :IPv4
AF_INET6 :IPv6
AF_UNIX :本地通讯
type:选择传输协议 tcp /udp
SOCK_STREAM ;tcp
SOCK_DGRAM : udp
protocol: 基本废弃,一般赋0

返回值:
成功返回描述网络套接字sockfd,失败返回-1

3.3:绑定ip和端口号等信息socket
用bind函数:
功能:
绑定一个端口号和 IP 地址,使套接口与指定的端口号和 IP 地址相关联。
原型:

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

头文件:
#include <sys/socket.h>

参数:

sockfd 为前面 socket 的返回值
my_addr:封装ip地址和端口号:

struct sockaddr //此结构体不常用
{
    
    
unsigned short int sa_family; //调用 socket()时
的 domain 参数,即 AF_INET 值。
char sa_data[14]; //最多使用 14 个字符长度
};

#include<netinet/in.h>
struct sockaddr_in //常用的结构体
{
    
    
unsigned short int sin_family; //AF_INET
uint16_t sin_port; //为使用的 port 编号
= htons(12345)
struct in_addr sin_addr; //为 IP 地址
unsigned char sin_zero[8]; //未使用
};

addrlen:第二个参数大小

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

3.4:设置允许的最大连接数:

listen函数:
功能:
使服务器的这个端口和 IP 处于监听状态,等待网络中某一客户机的连接请求。如果客户端有连接请求,端口就会接受这个连接。
原型:

  int listen(int sockfd, int backlog);

头文件:
#include <sys/socket.h>
参数:

sockfd 为前面 socket 的返回值.即 sfd
backlog 指定同时能处理的最大连接要求,通常为 10 或者 5。 最大值可设至 128

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

3.5:等待来自客户端的连接请求:
accept函数:
功能:
接受远程计算机的连接请求,建立起与客户机之间的通信连接
原型

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

头文件:
#include <sys/socket.h>
参数:

sockfd 为前面 socket 的返回值.即 sfd
addr:用于接受客户端的ip地址和端口号
addrlen:第二个参数大小

返回值:
返回新的套接字描述符,专门用于与建立的客户端通信,失败-1

3.6:收发数据:

TCP:
发送:
功能:
用新的套接字发送数据给指定的远端主机
原型

 ssize_t send(int s, const void *buf, size_t len, int flags);

头文件:
#include <sys/socket.h>
参数:

s:新的套接字
buf:要发送的数据缓冲区
len: 数据长度
flags: 一般赋0 .阻塞

返回值:
成功返回真正发送的数据长度,失败-1
接收:
功能:
用新的套接字来接收远端主机传来的数据,并把数据存到由参数 buf 指向的内存空间
原型:

ssize_t recv(int s, void *buf, size_t len, int flags);

头文件:
#include <sys/socket.h>
参数:

s:新的套接字
buf:存放接收数据的缓冲区
len: 数据长度
flags: 一般赋0 .阻塞

返回值:
成功返回真正接收的数据长度,失败-1

udp:
发送:
原型:

ssize_t sendto(int s, const void *buf, size_t len, int
flags, const struct sockaddr *to, socklen_t tolen);

头文件:
#include <sys/socket.h>
参数:

s:新的套接字
buf:要发送的数据缓冲区
len: 数据长度
flags: 一般赋0 .阻塞
to:服务器ip和端口号
tolen;上一个参数大小

返回值:
成功返回真正发送的数据长度,失败-1

接收:
原型:

ssize_t recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);

头文件:
#include <sys/socket.h>
参数:

s:新的套接字
buf:要发送的数据缓冲区
len: 数据长度
flags: 一般赋0 .阻塞
from:源机地址和端口号
tolen:地址长度

返回值:
成功返回真正接收的数据长度,失败-1

3.7:关闭网络连接:

close(sockfd);

客户端操作流程:

3.1: 创建socket,用socket函数;

3.2:设置要连接的服务器的ip地址和端口等属性
连接服务器

用connect函数:
功能:
用来请求连接远程服务器, 将参数 sockfd 的 socket 连至参数 serv_addr 指定的服务器 IP和端口号上去
原型:

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

头文件:
#include <sys/socket.h>
参数:

sockfd 为前面 socket 的返回值,即 sfd
serv_addr 为结构体指针变量,存储着远程服务器的 IP 与端口号信息。
addrlen 表示结构体变量的长度

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

3.3:收发数据,send和recv或者read和write
3.4:关闭网络连接

案例演示:
实现不同主机之间的服务器和客户端之间的通信交流:
(下面代码只能实现一台主机和服务器之间的通信)

参考代码:
sever.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#define PORT 6789
#define IP "192.168.43.156"
/*
 TCP 服务器
 1. 创建套节字
 2. 绑定 IP 端口
 3. 监听
 4. 等待连接
 5. 收发数据
 6. 关闭
*/
int main()
{
    
    
 int ret;
 //创建套节字
 int sockfd = socket(AF_INET,SOCK_STREAM,0);
 if(sockfd == -1)
 {
    
    
  perror("socket");
  return -1;
 }
 printf("连接套节字 创建成功\n");
 //绑定
 struct sockaddr_in addr,cli_addr;
 int len = sizeof(struct sockaddr_in);
 addr.sin_family = AF_INET;
 addr.sin_port = htons(PORT);
 addr.sin_addr.s_addr = inet_addr(IP);
 ret = bind(sockfd,(struct sockaddr *)&addr,len);
 if(ret == -1)
 {
    
    
  perror("bind");
  return -1;
 }
 printf("绑定成功\n");
 //监听
 ret = listen(sockfd,3);
 if(ret == 0)
  printf("监听成功\n");
 else
  return -1; 
 //等待连接
 int comfd = accept(sockfd,(struct sockaddr *)&cli_addr,&len);
 if(comfd == -1)
  return -1;
 printf("客户端 %s 已连接\n",inet_ntoa(cli_addr.sin_addr));
 //收发数据 
 char r_buf[100]={
    
    0};
 char w_buf[100]={
    
    0};
 while(1)
 {
    
    
  memset(r_buf,0,sizeof(r_buf));
  ret = recv(comfd,r_buf,sizeof(r_buf),0);
  if(ret == -1)
   return -1;
  printf("server recv: %s\n",r_buf);
  printf("server 发送:");
  memset(w_buf,0,sizeof(w_buf));
  scanf("%s",w_buf);
  send(comfd,w_buf,sizeof(w_buf),0);
 }
 //关闭
 close(sockfd);
 close(comfd);
 return 0;
}

client.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#define PORT 6789
#define IP "192.168.43.156"
/*
 TCP 客户端
 1. 创建套节字
 2. 连接服务器
 3. 收发数据
 4. 关闭
*/
int main()
{
    
    
 int ret;
 //创建套节字
 int sockfd = socket(AF_INET,SOCK_STREAM,0);
 if(sockfd == -1)
 {
    
    
  perror("socket");
  return -1;
 }
 printf("连接套节字 创建成功\n");
 //连接
 struct sockaddr_in addr;
 int len = sizeof(struct sockaddr_in);
 addr.sin_family = AF_INET;
 addr.sin_port = htons(PORT);
 addr.sin_addr.s_addr = inet_addr(IP);
 ret = connect(sockfd,(struct sockaddr *)&addr,len);
 if(ret == -1)
 {
    
    
  perror("bind");
  return -1;
 }
 printf("连接成功\n");
 //收发数据 
 char r_buf[100]={
    
    0};
 char w_buf[100]={
    
    0};
 while(1)
 {
    
     
  printf("client 发送:");
  memset(w_buf,0,sizeof(w_buf));
  scanf("%s",w_buf);
  send(sockfd,w_buf,sizeof(w_buf),0);
  memset(r_buf,0,sizeof(r_buf));
  ret = recv(sockfd,r_buf,sizeof(r_buf),0);
  if(ret == -1)
   return -1;
  printf("client recv: %s\n",r_buf);
  }
 //关闭
 close(sockfd);
 return 0;
}
ifconfig

在这里插入图片描述

运行结果:
在这里插入图片描述

补充:重要的数据结构

数据结构体

struct sockaddr {
unsigned short sa_family; /地址族/ ipv4 ipv6
char sa_data[14]; /*14 节的协议地址,包含该 socket 的 IP 地址和端口号。
*/
};

常用结构体

struct sockaddr_in {
__kernel_sa_family_t sin_family; /* short int型 地址族 2 个字节 Address family /
__be16 sin_port; /
unsigned short int 型 端口号 2 个字节,区分应用 Port number
/
struct in_addr sin_addr; /
IP 地址 4 个字节 Internet address */
/*填充 0 以保持与 struct sockaddr 同样大小 Pad to size of `struct sockaddr’.
*/
unsigned char __pad[SOCK_SIZE - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};

sa_family:
在这里插入图片描述

AF:
address family
地址族
PF:
procotol family
协议族

sa_data:
14字节的特定协议地址

参考结构流程图:
Linux网络编程
:需要使用xmind软件进行查看

猜你喜欢

转载自blog.csdn.net/weixin_40734514/article/details/109254288