网络编程-01网编概论+TCP

一、internet历史

1968年:ARPAnet阿帕网,是internet的雏形,传输数据不能跨主机、跨平台
1974年:TCP协议出现,能够实现跨主机平台操作,但是没有纠错功能
1983年:TCP/IP协议的出现
         能够跨主机平台进行数据传输
         能够进行数据纠错

协议:双方事先约定好的一组规则

二、网络协议模型

1.OSI七层协议模型

应用层:应用程序实现网络通信的接口
表示层:对数据进行加密解密解析
会话层:建立网络通信节点
传输层:实现点对点的通信
网络层:路由寻址
数据链路层:数据帧格式封装,实现数据纠错
物理层:屏蔽物理硬件差异,实现光电信号的转换

物、数、网、传、会、表、应

2.TCP/IP四层协议模型

应用层:HTTP(超文本传输协议)、FTP(文件传输协议)、NSF(网络挂载协议)、SSH(远程登录协议)
传输层:TCP协议、UDP协议
网络层:IP协议(路由寻址)、ICMP(跨传输层的通信协议)、IGMP(广播、组播)
物理网络接口层:以太网协议、ARP(ip->MAC)、RARP(MAC->ip)、ppp

TCP:
    面向连接,是一种安全可靠、有序的传输层协议,它能保证数据在传输过程中,不丢失、不失序
        应用场景:登录程序、传输重要文件

UDP:
    无连接,是一个不安全可靠的传输层协议,他不能保证数据在传输过程中,不出错、不丢失、不失序
        应用场景:流媒体软件、大型音视频传输

三、网络编程预备知识

1.IP地址

IP地址的作用:在网络中唯一标识一台主机
IP类型:
    IPV4:32bit-4字节数据
        表达形式:
            (1)点分十进制: "192.168.16.163"  是个字符串
            (1)二进制:    "1.1.1.1"----->
                            00000001 00000001 00000001 00000001
    
    IPV6:128bit

2.port --端口号

端口号:唯一标识一个进程,本质是一个unsigned short类型的数据
取值范围:0~65535  0不能使用
    1~1023:系统端口
    1024~5000:特殊应用程序
    5001~65535:系统预留给用户使用的端口

3.套接字 – socket

套接字的本质:特殊的文件描述符
    可以通过read/write进行数据传输

4.字节序

字节序:数据在内存中储存的方式

大端序(网络字节序):高位的数据存放在低地址位 
        arm架构、交换机、路由器
小端序(主机字节序):地位的数据存放在低地址位
        x86架构计算机
        
字节序转换函数:
    主机字节序转换为网络字节序:
        htons(6666);//将端口号6666转换为网络字节序    host to network 
    网络字节序转换为主机字节序:
        ntohs(6666);//将端口号6666转换为主机字节序

5.数据的封包和拆包

在这里插入图片描述

6.linux没有网络图标

重启网络管理员:
    sudo service network-manager restart

四、基于socket的TCP通信 --相关函数

在这里插入图片描述

1.创建套接字 – socket()

#include <sys/types.h>         
#include <sys/socket.h>

int socket(int domain, int type, int protocol);
返回值:成功返回套接字(sockfd),失败返回-1;
参数:
domain:地址族
    AF_UNIX:本地套接字
    AF_INET:IPV4     //PF_INET
    AF_INET6:IPV6
type:套接字类型
    SOCK_STREAM:流式套接字    //唯一对应TCP通信
    SOCK_DGARM:数据报套接字    //唯一对应UDP通信
protocol:默认填0

2.绑定本机IP地址和端口号 --bind()

#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
   
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
返回值:成功返回0,失败返回-1
参数:
    sockfd:socket函数创建得到的套接字
    addr:
        服务器地址结构的首地址
        注意地址结构体和参数不一致应该强转
    addrlen:
        服务器地址结构的大小
        
    IPV4对应的地址结构(每一个协议对应的地址结构不同,具体看手册):
    man 7 ip
               struct sockaddr_in {
               sa_family_t    sin_family; /* 地址族: 选择AF_INET */
               in_port_t      sin_port;   /* port in network byte order */
               struct in_addr sin_addr;   /* internet address */
           };

           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };
    
    
eg:    
    struct sockaddr_in caddr;
    caddr.sin_family=AF_INET;
    caddr.sin_port=htons(6666);        //注意字节序,打印时再用ntohs转回来
    caddr.sin_addr.s_addr=inet_addr("192.168.16.74")//注意字符串转整形,
    //绑定bind                                        //打印时用inet_ntoa()转回来
    bind(sockfd,(struct sockaddr*)&caddr,sizeof(caddr));
                    //注意强转
地址转换 inte_addr()/inet_ntoa()
unsigned long inet_addr(char *address);
功能:点分十进制(字符串)--->整型数
返回值:成功返回32bit的整型数,失败返回-1
参数:
    address:是以NULL结尾的点分十进制IPV4字符串
    eg:
        struct  in_addr addr;
        addr.s_addr = inet_addr("192.168.1.100");
        
char *inet_ntoa(struct in_arrr address);
功能:ip地址的整型数-->点分十进制(字符串)
返回值:成功返回字符串,失败返回NULL
参数:
    address:ip地址的整型数
字节序转换 htons()/ntohs()
字节序转换函数:
    主机字节序转换为网络字节序:
        htons(6666);//将端口号6666转换为网络字节序    host to network 
    网络字节序转换为主机字节序:
        ntohs(6666);//将端口号6666转换为主机字节序

3.设置监听套接字 --listen()

#include <sys/types.h>          
#include <sys/socket.h>

int listen(int sockfd, int backlog);
返回值:成功返回0,失败返回-1
参数:
    sockfd:套接字
    backlog:客户端连接等待的最大队列元素个数,
             但不是只能连接这么多个,连接后会退出队列,让后续网络进入队列

在这里插入图片描述
监听套接字

4.等待客户端连接 --accept()

#include <sys/types.h>         
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值:
    成功返回一个新的套接字,一般称他为通信套接字(connfd)或者读写套接字(rcvfd)
    失败返回-1
参数:
    sockfd:套接字
    addr:
        客户端地址结构的首地址,可以从该结构体中获取客户端的地址信息
        注意地址结构体和参数不一致应该强转
    addrlen:
        客户端地址结构的大小的地址

5.向服务器发起连接 --connect()

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
返回值:成功返回0,失败返回-1
参数:
    sockfd:套接字
    addr:连接服务器的地址结构的首地址
          注意地址结构体和参数不一致应该强转
    addrlen:地址结构的大小
    
注:和服务器的绑定代码一样        

eg:客户端给服务器发送消息,服务器接受消息

服务器:

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{ 
    //1、创建套接字 -- socket()
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if(sockfd < 0)
    {   
        perror("socket");
        exit(-1);
    }   
    printf("socket successful!\n");

    //2、绑定本机IP地址和端口号
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;  //选择ipv4协议
    saddr.sin_port = htons(6666);
    saddr.sin_addr.s_addr = inet_addr("192.168.16.163");  //将点分十进制转换为整形之后再赋值
    //saddr.sin_addr.s_addr = INADDR_ANY;

    int s_len = sizeof(saddr);  //计算服务器地址结构的大小

    int ret = bind(sockfd, (struct sockaddr *)&saddr, s_len);
    if(ret < 0)
    {
        perror("bind");
        exit(-1);
    }
    printf("bind successful!\n");

    //3、设置监听套接字 -- listen()
    ret = listen(sockfd, 7);
    if(ret < 0)
    {
        perror("listen");
        exit(-1);
    }
    printf("listen successful!\n");

    //4、等待客户端连接

    struct sockaddr_in caddr;
    memset(&caddr, 0, sizeof(caddr));

    int c_len = sizeof(caddr);
    while(1)
    {
        printf("wait for a new client...\n");
        int connfd = accept(sockfd, (struct sockaddr *)&caddr, &c_len);
        if(connfd < 0)
        {
            perror("accept");
            exit(-1);
        }

        printf("link successful!  ip -- %s  port -- %d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));


        //5、数据的发送或接收
        char buf[64] = {0};

        while(1)
        {
            memset(buf, 0, 64);
            ret = read(connfd, buf, 64);
            if(ret < 0)
            {
                perror("read");
                exit(-1);
            }
            if(ret == 0)
            {
                //printf("a client leave!\n");
                printf("%s leave!\n", inet_ntoa(caddr.sin_addr));
                break;
        }
            printf("recv %dbytes:%s\n", ret, buf);
        }

        //6、关闭套接字
        close(connfd);
    }
    return 0}
                                 

客户端:

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    //1、创建套接字 -- socket()
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        perror("socket");
        exit(-1);
    }
    printf("socket successful!\n");

    //2、向服务器发起连接
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;  //选择ipv4协议
    saddr.sin_port = htons(6666);
    saddr.sin_addr.s_addr = inet_addr("192.168.16.163");  //将点分十进制转换为整形之后再赋值


    int s_len = sizeof(saddr);  //计算服务器地址结构的大小

    int ret = connect(sockfd, (struct sockaddr *)&saddr, s_len);
    if(ret < 0)
    {
        perror("connect");
        exit(-1);
    }
    printf("link successful!\n");

    //3、数据的发送或接收


    char buf[64] = {0};
    while(1)
    {
        fgets(buf, 64, stdin);
        buf[strlen(buf)-1] = '\0';

        ret = write(sockfd, buf, strlen(buf));
        if(ret < 0)
        {
            perror("write");
            exit(-1);
        }
       }
    }
    //4、关闭套接字
    close(sockfd);

    return 0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值