网络编程学习

在这里插入图片描述
在这里插入图片描述
首先简单说一下OSI参考模型,OSI将网络分为七层,自下而上分别是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,而TCP/IP体系结构则将网络分为四层,自下而上分别是网络接口层、网络层、传输层、应用层
在这里插入图片描述
看上面的图,发送端想要发送数据到接收端。首先应用层准备好要发送的数据,然后给了传输层,传输层的主要作用就是为发送端和接收端提供可靠的连接服务,传输层将数据处理完后就给了网络层。网络层的功能就是管理网络,其中一个核心的功能就是路径的选择(路由),从发送端到接收端有很多条路,网络层就负责管理下一步数据应该到哪个路由器。选择好了路径之后,数据就来到了数据链路层,这一层就是负责将数据从一个路由器送到另一个路由器。然后就是物理层了,可以简单的理解,物理层就是网线一类的最基础的设备。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

先来看一下百度百科对于TCP协议的定义:传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。(UDP(User Datagram Protocol: 用户数据报协议),UDP协议: 用户数据协议
1.将数据、源、目的封装成数据包,不需要建立连接
2.每个数据包的大小限制在64k内,不适合传输大量数据
3.因无需连接,故是不可靠的
4.发送数据结束时无需释放资源(因为不是面向连接的),速度快

TCP协议: 传输控制协议
1.使用TCP协议前,须先建立TCP连接,形成传输数据通道
2.传输前,采用"三次握手"方式,是可靠的
3.TCP协议进行通信的两个应用进程: 客户端、服务端
4.在连接中可进行大数据量的传输
5.传输完毕,需释放已建立的连接,效率

在这里插入图片描述
百度百科对于Socket的介绍:套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。
我们将一个小区比作一台计算机,一台计算机里面跑了很多程序,怎么区分程序呢,用的是端口,就好像小区用门牌号区分每一户人家一样。手机送到小明家了,怎么进去呢?从大门进啊,怎么找到大门呢?门牌号呀。不就相当于从互联网来的数据找到接收端计算机后再根据端口判断应该给哪一个程序一样吗。小明家的入口就可以用小区地址+门牌号进行唯一表示,那么同样的道理,程序也可以用IP+端口号进行唯一标识。那么这个程序的入口就被称作Socket。
ps:socket相当于网络层的门卫,当数据由路由器过时,判断ip和端口是否属于该主机的,是的话就接受数据。
ps:传输层即主机到主机的层次。传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输。此外,传输层还要处理端到端的差错控制和流量控制问题。这里的端不是上面的端口,端口主要还是程序接口。
五大层内容:
物理层:物理层的任务就是透明地传送比特流。(注意:传递信息的物理媒体,如双绞线、同轴电缆、光缆等,是在物理层的下面,当做第0 层。)物理层还要确定连接电缆插头的定义及连接法。
数据链路层:将网络层交下来的IP数据报组装成帧,在两个相邻结点间的链路上”透明“的传送以帧为单位的数据。每一帧包括数据和必要的控制信息。在收到数据时,控制信息使收到端直到哪个帧从哪个比特开始和结束(打包数据)。
网络层:选择合适的路由,使发送站的运输层所传下来的分组能够正确无误地按照地址找到目的站,并交付给目的站的运输层。网络层将运输层产生的报文或用户数据报封装成分组(IP数据报)或包进行传送。
运输层:向上一层应用层的进行通信的两个进程之间提供一个可靠的端对端服务,使它们看不见运输层以下的数据通信的细节。(TCP、UDP)
应用层:直接为用户的应用进程提供服务(HTTP、FTP等)
各层的作用:
**物理层:
采用怎样的传输媒体(介质)?
采用怎样的物理接口?
使用怎样的信号表示比特0和1?
解决以上问题后就可以实现01信号在计算机之间的传输。
数据链路层:
如何标识网络中的各主机(主机编址问题,例如MAC地址)?
如何从信号所表示的一连串比特流中区分出地址和数据?
如何协调各主机通信(例如,各主机争用总线,交换机的实现原理)?
解决此问题后可以实现分组在一个网络上传输。
网络层:
如何标识各网络以及网络中的各主机(网络和主机共同编址的问题,例如IP地址)?
路由器如何转发分组,如何进行路由选择?
解决此问题后可以实现分组在网络间传输。
运输层:
如何解决进程之间基于网络的通信?
出现传输错误时如何处理?
解决此问题后可以实现进程之间基于网络的通信。
应用层:
通过应用进程间的交互来完成特定的网络应用。
例如:支持万维网应用的HTTP协议,支持电子邮件的SMTP协议,支持文件传送的FTP协议。

在这里插入图片描述
理解:简单地说,为了实现跨越互联网的,主机 A 的进程 P1,和主机 B 的进程 P2 之间的通信,我们逐层把这个任务交给 TCP/IP 协议栈。运输层:“如果有人能帮我把数据从某个网络中的机器 A 搬到另一个网络中的机器 B,我就可以搞定这个任务,因为我知道不同的数据应该交给机器上的哪个进程。”网络层:“如果有人能帮我把数据从局域网中直接相连的一台机器搬到另一台机器,我就可以把数据从一个网络搬到另一个网络,因为我知道路线怎么走,要经过哪些节点。”链路层:“我知道怎样在局域网中搬数据,还能用 CSMA/CD 协议协调工作,还能用 CRC32 校验发送的数据和接收的数据是一致的,blabla… But,我只是说说,我不干苦力活。”物理层:“楼上的大爷们发话了,兄弟们上。”
地址:硬件地址是数据链路层和物理层使用的地址
IP地址是网络层和以上各层使用的地址,是一种逻辑地址,ip地址的组成 = 网络地址 + 主机地址
IP地址放在IP数据报的首部,而硬件地址放在MAC帧的首部。当数据报放入数据链路层的MAC帧中后,整个IP数据报就成为MAC帧的数据,因而在数据链路层看不见数据报的IP地址。

在这里插入图片描述
在这里插入图片描述
一句话总结:网关,通过字面意思解释就是网络的关口。从技术角度来解释,就是连接两个不同网络的接口,比如局域网的共享上网服务器就是局域网和广域网的接口。在这里插入图片描述
在这里插入图片描述
ps:eth为帧头帧尾

计算机网络中性能指标:
1速率:
比特:计算机中数据量的单位,也是信息论中信息量的单位。一个比特就是二进制数字中的一个1或0。
基本单位:bit(b) 比特

     		8 bit = 1 Byte
            KB = 2^10B            
            MB = K KB = 2^20 B              
            GB = K MB = 2^30 B              
            TB = K GB = 2^40 B

速率就是连接在计算机网络上的主机在数字信道上传送比特的速率,也称为比特率或数据率。
基本单位:bit/s(b/s,bps)

			kb/s = 10^3b/s	
            Mb/s = K Kb/s = 10^6 b/s           
            Gb/s = k Mb/s = 10^9 b/s       
            Tb/s = k Gb/s = 10^12 b/s

2.带宽:
带宽在模拟信号系统中表示的是信号所包含的各种不同频率成分所占据的频率范围,也就是传输过程中最大频率与最小频率的范围
3.吞吐量:
吞吐量表示在单位时间内通过某个网络(或信道、接口)的数据量。
4.时延:
发送时延:源主机将分组发送出去产生的时延。
5.丢包率:
丢包率即分组丢失率,是指在一定的时间范围内,传输过程中丢失的分组数量与总分组数量的比率。
丢包率具体可分为接口丢包率、结点丢包率、链路丢包率、路径丢包率、网络丢包率等
socket:
TCP的“三报文握手”建立连接。
在这里插入图片描述
第一次握手:客户发送请求,此时服务器知道客户能发;
第二次握手:服务器发送确认,此时客户知道服务器能发能收;
第三次握手:客户发送确认,此时服务器知道客户能收。
第一次:客户向服务器发送连接请求段,建立连接请求控制段(SYN=1),表示传输的报文段的第一个数据字节的序列号是x,此序列号代表整个报文段的序号(seq=x);客户端进入 SYN_SEND (同步发送状态);

第二次:服务器发回确认报文段,同意建立新连接的确认段(SYN=1),确认序号字段有效(ACK=1),服务器告诉客户端报文段序号是y(seq=y),表示服务器已经收到客户端序号为x的报文段,准备接受客户端序列号为x+1的报文段(ack_seq=x+1);服务器由LISTEN进入SYN_RCVD (同步收到状态);

第三次:客户对服务器的同一连接进行确认.确认序号字段有效(ACK=1),客户此次的报文段的序列号是x+1(seq=x+1),客户期望接受服务器序列号为y+1的报文段(ack_seq=y+1);当客户发送ack时,客户端进入ESTABLISHED 状态;当服务收到客户发送的ack后,也进入ESTABLISHED状态;第三次握手可携带数据;

linux下网络编程

网络中进程通信:
进程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施。
他们都仅限于用在本机进程之间通信。网间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。为此,首先要解决的是网间进程标识问题。同一主机上,不同进程可用进程号(process ID)唯一标识。但在网络环境下,各主机独立分配的进程号不能唯一标识该进程(如a电脑的进程号5和b电脑的进程号5不是同一个)。
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

socket套接字:

 socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,        socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).
 说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
 其socket也有自己的描述符:当应用程序要创建一个套接字时,操作系统就返回一个小整数作为描述符,应用程序则使用这个描述符来引用该套接字,需要I/O请求的应用程序请求操作系统打开一个文件。

ps:科普一下文件描述符和文件指针的区别:
文件描述符:在linux系统中打开文件就会获得文件描述符,它是个很小的正整数。每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。
文件指针:C语言中使用文件指针做为I/O的句柄。文件指针指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄)。
在这里插入图片描述
服务器端先初始化Socket,然后与端口绑定(bind)(所谓绑定(bind)是指别人连接我只能通过我所绑定的端口),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

具体函数实现:

原文链接:
https://blog.csdn.net/hguisu/article/details/7445768
socket()函数
在这里插入图片描述
当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。
bind()函数
在这里插入图片描述
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
在这里插入图片描述
在这里插入图片描述
ps:服务器端的sockfd和客户端sockfd不是同一个,由各自的socket()函数生成,其中上面的所有地址都是指服务器端地址!!但是下面这个accept()的地址是客户端地址,即客户端连接服务器connect()是服务器地址,服务器accpet()接受客户端连接是客户端地址!!!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三次握手:
在这里插入图片描述

四次释放:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参考代码:
服务器:

/* File Name: server.c */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define DEFAULT_PORT 8000
#define MAXLINE 4096
int main(int argc, char** argv)
{
    int    socket_fd, connect_fd;
    struct sockaddr_in     servaddr;
    char    buff[4096];
    int     n;
    //初始化Socket
    if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
    printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }
    //初始化
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
    servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT
 
    //将本地地址绑定到所创建的套接字上
    if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
    printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }
    //开始监听是否有客户端连接
    if( listen(socket_fd, 10) == -1){
    printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }
    printf("======waiting for client's request======\n");
    while(1){
//阻塞直到有客户端连接,不然多浪费CPU资源。
        if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){
        printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
        continue;
    }
//接受客户端传过来的数据
    n = recv(connect_fd, buff, MAXLINE, 0);
//向客户端发送回应数据
    if(!fork()){ /*紫禁城*/
        if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)
        perror("send error");
        close(connect_fd);
        exit(0);
    }
    buff[n] = '\0';
    printf("recv msg from client: %s\n", buff);
    close(connect_fd);
    }
    close(socket_fd);
}

客户端:

/* File Name: client.c */
 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
 
#define MAXLINE 4096
 
 
int main(int argc, char** argv)
{
    int    sockfd, n,rec_len;
    char    recvline[4096], sendline[4096];
    char    buf[MAXLINE];
    struct sockaddr_in    servaddr;
 
 
    if( argc != 2){
    printf("usage: ./client <ipaddress>\n");
    exit(0);
    }
 
 
    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
    exit(0);
    }
 
 
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(8000);
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
    printf("inet_pton error for %s\n",argv[1]);
    exit(0);
    }
 
 
    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
    printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }
 
 
    printf("send msg to server: \n");
    fgets(sendline, 4096, stdin);
    if( send(sockfd, sendline, strlen(sendline), 0) < 0)
    {
    printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
    exit(0);
    }
    if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) {
       perror("recv error");
       exit(1);
    }
    buf[rec_len]  = '\0';
    printf("Received : %s ",buf);
    close(sockfd);
    exit(0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值