网络编程-网络基础

IO进程: 进程和进程之间的通信 - 信号 信号量 消息队列 有名管道 无名管道 共享内存 套接字

套接字: 不同主机 不同操作系统之间的 进程通信

干什么: 实现无线

局域网:同一局域网下IP网段一致

IP地址

  1. IP地址 是 网络中的 主机的标识, 本质是二进制数字。

  2. IP采用 点分十进制 表示

3) IP分类: 分为 IPV4 和 IPV6 (IPV6表示的范围更广)

4) IP长度 32位 (IPV4) 64位(IPV6)

5) 每个数据包 必须要携带 目标 IP 和 源IP地址

二级划分

IP=网络号+主机号

网络号:表示是否再同一个网段内(主要是同一网段,网络号是一样的)

主机号:本网段内主机的id(主机号在同一网段下,是唯一的)

二级划分的分类

IP二级划分所表示的范围

|----|-----------------------------|----------------------|
| A类 | 0.0.0.0 - 127.255.255.255 | 大型网络 |
| B类 | 128.0.0.0 - 191.255.255.255 | 中型网络 : 管理 和 监督互联网的组织 |
| C类 | 192.0.0.0 - 223.255.255.255 | 小型网络:家用网络 ,教室网络 |
| D类 | 224.0.0.0 - 239.255.255.255 | 用于 UDP的组播通信 |
| E | 240.0.0.0 - 255.255.255.255 | 保密单位:实验室, 军方 |

特殊的IP地址

不能分配给主机使用的地址

网络地址:标识网络的起始地址,该地址不会分配到主机。(表示方式:主机号全为0的地址,为网络地址)

例: 192.168.50. 0 主机号为 0 代表 网络地址, 不会被主机分配

广播地址:用于给局域网下的所有主机发送数据使用,不会分配到主机(表示方式:主机号全为1的地址,为广播地址)

练习:

IP为192.168.1.0,同一网段最多可以连接多少个主机?

c类,最后8位为主机号,网络地址和广播地址不会被分配,256-2=254

子网掩码

作用:辅助标记IP的网络号和主机号(更快的去区分网络和主机号)

特点:网络号全置为1,主机号全部置为0

练习:

子网掩码为 255.255.255.0, 该网段最多可以容纳多少台主机

c类,最后8位为主机号,网络地址和广播地址不会被分配,256-2=254

三级划分

作用:在二级划分的基础上,再次划分,提高IP的利用率

IP=网络号+子网号+主机号

子网号:从主机号中划分出几位,充当网络号。

练习:

  1. 已知一个子网掩码号为255.255.255.192,问,最多可以连接多少台主机?

C类 255.255.255.0 - 》三级划分 -》 192 -》 1100 0000

根据子网掩码特点: 主机号全为 0

0 - 63 -》 64 -》 去掉网络地址 和 主机地址 -》 62

  1. 有两台电脑主机,在最少浪费IP地址的情况下.将172.16.14.4与172.16.13.2划归为同一网段,子网掩码应该设置为

14: 0000 11 10 255.255.252.0

13: 0000 11 01

  1. 已知IP: 192.168.50.183, 子网掩码: 255.255.255.128, 问该IP的网段为多少?

192.168.50.183 1100 0000.1010 1000. 0011 0010. 1 011 0111

子网掩码: 1111 1111. 1111 1111. 1111 1111. 1 000 0000

193.168.50.128

  1. 通过子网掩码 255.255.255.128 该子网掩码可以划分几个子网网段?

C类 -》 1 000 0000 >> 两个子网网段

0

1

2

  1. 某公司有四个部门:行政、研发1、研发2、营销,每个部门各30台计算机接入公司局域网交换机,在192.168.1.0网

段内为每个部门划分子网,子网掩码应该怎么设置,每个子网的地址范围分别是什么?(4个部门之间不能通信)

255.255.255.192

范围:

192.168.1.0-192.168.1.63

192.168.1.128-192.168.1.192

等(自己算)

网络模型

网络模型采用分层的方式,每层实现不同的功能

网络中的数据包的传输流程

osI和TCP/IP的模型对应图

UDP和TCP

相同点:都属于传输层协议,都是全双工的通信

TCP-传输控制协议

该协议是一种高可靠性的有连接的协议

TCP容易粘包

*可靠性的评判标准:

数据无丢失, 数据无失误, 数据无失序, 数据无重复到达

TCP为什么具有高可靠性( 重点

三次握手和四次挥手机制

序列号和应答号机制

超时/错误重传机制

拥堵和流量控制机制

TCP的应用场景

对于传输质量要求较高的场合,以及大量数据传输的场合。

UDP-用户数据报协议

该协议是一种不可靠的无连接的协议

UDP是一种容易造成丢包的协议,不保证数据的完整性

UDP的应用场景

应答较为困难的网络中可以使用UDP。

socket套接字

什么是socket

  1. socket是一个编程接口
  2. socket是一个特殊的文件描述符
  3. socket是一种通信机制
  4. 一套用于建立连接的数字

socket的类型

流式套接字(SOCK_STREAM)对应协议-TCP

特点:面向连接,可靠性高的数据传输服务

数据报套接字(SOCK_DGRAM)对应协议-UDP

特点:无连接的,不可靠的数据传输服务

原始套接字(SOCK_RAM)

特点:较低层次的协议,例入ICMP中使用

socket的功能

socket可以在计算机中创建两个缓存区,一个是发送缓存区,一个是接收缓存区。

端口号

为了区分一台主机接收到的数据包,应该交给那个进程来处理

端口号的长度:2byte(IP长度为4byte)

众所周知端口(被占用): 0~1023(1~255之间为众所周知端口,通常由UNIX系统占用)

比如 文件传输端口 TFTP 端口号为 69

已登记端口:1024~49151 (---- 可用来建立与其它主机的会话**----)**

动态或私有端口:49152~65535--固定某些服务使用--

字节序

字节序:不同类型的CPU主机,内存存储大于一个字节类型的数据,在内存中的存放顺序

分类:

主机字节序(小端):地址低位存放数据低位,地址高位存放数据高位

网络字节序(大端):地址高位存放数据低位,地址地位存放数据高位

在主机上的字节序一般都为主机字节序。在网络中传输的数据,大于一个字节的数据类型,必须转换为网络字节序

端口号转换专用接口

头文件: #include<arpa/inet.h>
原型:  u_long htonl (u_long hostlong)     u_short htons (u_short short)
//端口号一般为 1024 - 49151, 两个字节足够,基本不需要long
功能: 主机字节序的端口 转 网络字节序 
           
原型:  u_long ntohl (u_long hostlong);   u_short ntohs (u_short short);
功能: 网络字节序的端口 转 主机字节序

IP转换专用接口

 in_addr_t  inet_addr(const char *strptr);
头文件:   #include<sys/socket.h>   #include<netinet/in.h>    #include<arpa/inet.h>
原型:       //该参数是字符串
功能:    主机字节序(点分十进制形式的IP) 转为网络字节序
参数:     const char *strptr: 字符串

       typedef uint32_t in_addr_t;  (通过vi -t 追一下)
            struct in_addr { 
                        in_addr_t   s_addr;
            }; 
返回值: 返回一个无符号长整型数(无符号32位整数用十六进制表示), 
            否则NULL

char *inet_ntoa(struct in_addr in);
头文件 :   #include <arpa/inet.h>  #include<sys/socket.h>  #include<netinet/in.h>              
功能:    将网络字节序二进制地址转换成主机字节序。 
参数:     stuct in_addr in addr  : 只需传入一个结构体变量,该变量代表IP
返回值:  返回一个字符指针, 否则NULL;

TCP编程

socket创建套接字

函数原型:
int socket(int domain, int type, int protocol);

调用形式:
socket(协议族,套接字类型,0);

参数domain:协议族
参数type:套接字类型
参数protocol:传0,表示根据第二个参数自动匹配协议

返回值:创建成功返回sockfd描述符(0->标准输入,1->标准输出,2->标准错误,3->自定义创建的socket)
        创建失败返回-1,更新errno

bind绑定套接字

vi -t :查询数据类型的shell指令

函数原型:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
头文件: #include<sys/types.h>  #include<sys/socket.h> 
         #include<netinet/in.h>  #include<netinet/ip.h>

功能:绑定 IP 和 port

参数:
    sockfd:套接字
    addr:用于通信结构体 (提供的是通用结构体,需要根据选择通信方式,填充对应结构体-通信当时socket第一个参数确定,需要强转)
         (结构体之间的强转,不可以直接使用普通数据类型强转,因为结构体字节对齐原则,具体大小不一致,会数据丢失,所以可使用结构体指针,对结构体地址进行强转)   
    addrlen:结构体大小   
    
返回值:成功 0   失败-1,更新errno
  
 通用结构体:
  struct sockaddr {
     sa_family_t  sa_family;
     char        sa_data[14];
 }

ipv4通信结构体:
struct sockaddr_in {
    sa_family_t    sin_family;  ----协议族
    in_port_t      sin_port;   ----端口
    struct in_addr sin_addr;     ----ip结构体
};
struct in_addr {
    uint32_t       s_addr;     --ip地址
};

listen监听

int listen(int sockfd, int backlog);
功能:监听,将主动套接字变为被动套接字
参数:
 sockfd:套接字
 backlog:等待连接队列中,客户端请求链接的最大个数,不能写0.
        一般写6-8个

返回值:成功 0   失败-1,更新errno  

accept阻塞等待连接

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

功能:阻塞函数,阻塞等待客户端的连接请求,如果有客户端连接,
             则accept()函数返回,返回一个用于通信的套接字文件;
参数:
   Sockfd :套接字
   addr: 链接客户端的ip和端口号
      如果不需要关心具体是哪一个客户端,那么可以填NULL;
   addrlen:结构体的大小
     如果不需要关心具体是哪一个客户端,那么可以填NULL;
返回值: 
     成功:通信的文件描述符; 
     失败:-1,更新errno新errno  

recv接收数据

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能: 接收数据 
参数: 
    sockfd: acceptfd ;
    buf  存放位置
    len  大小
    flags  一般填0
             MSG_DONTWAIT  非阻塞
返回值: 
   < 0  失败出错  更新errno
   ==0  表示客户端退出
   >0   成功接收的字节个数

练习

  1. 服务器可以循环接收客户端的数据;

  2. 当客户端退出后, 服务器阻塞等待下一个客户端的连接,而后继续通信;

  3. 当有客户端连接时, 服务器端 打印客户端的IP 和 Port信息;

  4. 将代码的 send 和 recv 改为 write 和 read, 测试一下效果;

  5. 利用argv[ ] 采用终端输入的方式, 输入IP 和 Port ,从而bind绑定;

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <pthread.h>
    #include <semaphore.h>
    #include <wait.h>
    #include <signal.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    #include <semaphore.h>
    #include <sys/msg.h>
    #include <sys/shm.h>
    #include <sys/un.h>

    typedef struct sockaddr_in addr_in_t;
    typedef struct sockaddr addr_t;
    typedef struct sockaddr_un addr_un_t;
    int main(int argc, const char *argv[])
    {
    while(1)
    {
    //创建套接字
    //AF_INET---ipv4协议族
    //SOCK_STREAM---流式套接字(TCP)
    //0---根据第二个参数自动匹配协议
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
    perror("socket is err");
    return -1;
    }

     	//bind绑定套接字
     	struct sockaddr_in saddr;
     	saddr.sin_family = AF_INET;
     	//将主机字节序的端口号转换为网络字节序
     	int port;
     	char p[128]={0};
     	printf("请输入Port:");
     	scanf("%d",&port);
     	printf("请输入IP:");
     	scanf("%s",p);
     	saddr.sin_port = htons(port);
     	saddr.sin_addr.s_addr = inet_addr(p);
    
    
     	//绑定填充的结构体属性到sockfd套接字上
     	int bindfd = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
     	if(bindfd<0)
     	{
     		perror("bind is err");
     		//return -1;
     	}
     	printf("%ld %ld\n",sizeof(saddr),sizeof(struct sockaddr_in));
    
     	//listen监听 创建监听队列
     	int listenfd = listen(sockfd,5);
     	if(listenfd < 0)
     	{
     		perror("listen is err");
     		return -1;
     	}
    
     	//建立通信
     	//如果没有客服端链接,accept回阻塞等待客户端链接
     	//第二个参数用于获取来链接的客服端的信息
     	//返回值为一个进行通信的文件描述符
     	printf("accept.......\n");	
     	struct sockaddr_in aaddr;
     	int len = sizeof(aaddr);
     	aaddr.sin_family = AF_INET;
     	//int acceptfd = accept(sockfd,NULL,NULL);	
     	int acceptfd = accept(sockfd,(struct sockaddr*)&aaddr,&len);	
     	int kfport = ntohs(aaddr.sin_port);
     	char* kfip = inet_ntoa(aaddr.sin_addr);
     	printf("客服端端口:%d\n客服端IP为:%s\n",kfport,kfip);
     	if(acceptfd < 0)
     	{
     		perror("accept id err");
     	char buf[128]={0};
     		return -1;
     	}
    
     	//接收数据
     	//accept是建立通信的文件描述符(不能用sockfd)
     	//第四个参数常用0和MSG_NOWAIT
     	//0---表示阻塞,如果没有数据接收,则阻塞等待
     	//MSG_NOWAIT---表示非阻塞
     	while(1)
     	{
     		char buf[128]={0};
     		int recfd = recv(acceptfd,buf,sizeof(buf),0);
     		if(recfd < 0)
     		{
     			perror("recv is err");
     			return -1;
     		}
     		else if(recfd == 0)
     		{
     			printf("client is exit\n");
     			break;
     		}
     		else
     		{
     			printf("client输入的数据为:%s\n",buf);
     		}
     	}
    
     	close(sockfd);
     	close(acceptfd);
     }
     return 0;
    

    }

相关推荐
Envyᥫᩣ5 分钟前
C#语言:从入门到精通
开发语言·c#
童先生27 分钟前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu28 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
方方怪30 分钟前
与IP网络规划相关的知识点
服务器·网络·tcp/ip
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
老秦包你会1 小时前
Qt第三课 ----------容器类控件
开发语言·qt
凤枭香1 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
ULTRA??1 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
远望清一色1 小时前
基于MATLAB的实现垃圾分类Matlab源码
开发语言·matlab
weixin_442643421 小时前
推荐FileLink数据跨网摆渡系统 — 安全、高效的数据传输解决方案
服务器·网络·安全·filelink数据摆渡系统