【网络编程】TCP/IP (客户端--服务端)

数据链路层: 通过各种控制协议,将有差错的物理信道变为无差错的、能
可靠传输数据帧的数据链路。
MAC(物理地址)48位
网络层: 实现数据包的选路和转发。
IP 地址有分 IPV4 (32位)和 IPV6 (128位)两种类别格式,(主机号和网络号构成)
传输层:传输层为应用层提供过了一个进程间通讯的途径 (TCP/UDP/SCTP)
OSI七层协议,TCP/IP五层协议
寄快递,ip /协议 发送的数据大小有限制。
tcp/ip 面向连接的可靠的 流式服务
请添加图片描述

  • 主机字节序列和网络字节序列
    主机字节序列分为大端字节序列(高位数,低地址)和小端字节序列。
    两台不同字节序列的主机传递数据,可能会混乱。即:大端字节序列称为网络字节序列。接收方根据自己字节进行转换。
    因此整型数据发送到网络,规定为大端序列字节
    发送数据的时候,其字节会从(长整型,短整型主机字节转为网络字节),收数据相反。
  • linux通过四个函数完成主机字节序列和网络字节序列之间的转换。 头文件: #include <netinet/in.h>
 uint32_t htonl(uint32_t hostlong);// 长整型的主机字节序转网络字节序
 uint32_t ntohl(uint32_t netlong); // 长整型的网络字节序转主机字节序
 uint16_t htons(uint16_t hostshort); // 短整形的主机字节序转网络字节序

 uint16_t ntohs(uint16_t netshort);// 短整型的网络字节序转主机字节

套接字:
通过套接字进行收发数据。(相当于手机)
ip和端口填充到套接字的地址(结构体sockaddr中)
#include <bits/socket.h>

socket

int socket(int domain, int type, int protocol)
//socket()创建套接字,成功返回套接字的文件描述符,失败返回-1
// domain: 设置套接字的协议簇, AF_UNIX AF_INET AF_INET6
 //type: 设置套接字的服务类型 SOCK_STREAM SOCK_DGRAM
 //protocol: 一般设置为 0,表示使用默认协议
  • 人们习惯用点分十进制字符串表示 IPV4 地址,但编程中我们需要先把它们转化
    为整数方能使用,下面函数可用于点分十进制字符串表示的 IPV4 地址和网络字节序整数表示的 IPV4地址之间的转换:
    IPV6 地址,要用网络字节序表示

bind() 设置主机的ip地址和端口

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//bind()将 sockfd 与一个 socket 地址绑定,成功返回 0,失败返回-1
//sockfd 是网络套接字描述符
//addr 是地址结构   设置ip地址和端口
//addrlen 是 socket 地址的长度

  1. 通用套接字地址结构:
    sockaddr

  2. 专用套接字地址结构:
    IPV4:
    TCP/IP协议族有sockaddr_in :设置ip端口
    IPV6:
    sockaddr_in6

listen()监听队列

1,存放未完三次握手的链接。
2,存放已经完成三次握手的链接

int listen(int sockfd, int backlog);
//listen()创建一个监听队列以存储待处理的客户连接,成功返回 0,失败返回-1
//sockfd 是被监听的 socket 套接字
//backlog 表示处于完全连接状态的 socket 的上限(完成三次握手的链接的个数)
   //linux 上是 5

accept()

accept()处理存放在 listen 创建的已完成三次握手的队列中的连接。每处理一个连接,则
accept()返回该连接对应的套接字描述符。
如果队列为空,则阻塞。

connect()

一般由客户端程序执行。指定服务器端的ip地址和端口。
进行三次握手,建立链接

send()/recv

:收发数据。向缓冲区写入和读取数据

close()

关闭TCP链接,进行四次挥手
请添加图片描述

在写程序之前ping 127.0.0.0一下,看客户端与服务器端是否联通。

struct in_addr
 {
 u_int32_t s_addr;
//sin_addr: IPV4 地址结构:s_addr 以网络字节序表示 IPV4 地
};

struct sockaddr_in
 {
sa_family_t sin_family;
//sin_family: 地址族 AF_INET
 struct in_addr sin_addr;
 //sin_port: 端口号,需要用网络字节序表示

 };

服务器端

struct sockaddr_in saddr,caddr; //专用套接子地址结构,设置主机ip地址和端口
memset(&saddr,0,sizeof(saddr)); //将初始值置为0
saddr.sin_family = AF_INET; //设置地址组协议
saddr.sin_port = htons(6000); //端口/ 小端存放转大端存放-----主机字节序列转网络字节序列
// 发送数据的时候,其字节会从(长整型,短整型主机字节转为网络字节),收数据相反。
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");//设置ip地址

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
        int sockfd = socket(AF_INET,SOCK_STREAM,0);
                         //套接子协议(AF_INET 表示IPV4,AF_INET6 :IPV6)
                         //TCP 数据传输为数据流 ,SOCK_STREAM
                         //默认协议,一般为0
         if(sockfd == -1)
         {
               exit(1);
          }
        struct sockaddr_in saddr,caddr;  //专用套接子地址结构,设置主机ip地址和端口
        memset(&saddr,0,sizeof(saddr)); //将初始值置为0
        saddr.sin_family = AF_INET;  //设置地址组协议
        saddr.sin_port = htons(6000);   //端口/ 
        saddr.sin_addr.s_addr = inet_addr("0.0.0.0");//设置ip地址

        int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//强转为通用套接子地址结构。
        if(res== -1)
        {
          printf("bind falied");
          exit(1); 
        }

       res =  listen(sockfd,5);   //监听套接子(已经完成三次握手和未完成三次握手)
        if(res == -1)
        {
        close(sockfd);
        exit(1);
        }
        while(1)
        {
           int len = sizeof(caddr);      // caddr:那个客户端成功连接。那么caddr存放的就该ip地址和端口号。
           int c = accept(sockfd,(struct sockaddr*)&caddr,&len);//阻塞
             // 返回的该连接的连接套接子,处理已经完成三次握手的连接
            if(c == -1)
            {
                     continue;
            }
            printf("accept client ip :%s,port = %d\n",inet_ntoa(caddr.sin_addr),nthons(caddr.sin_port))//将ip地址幻化为点分十进制的整型。nthons网络转主机
            char buff[128]  ={0};
            int n = recv(c,buff,127,0);
            printf("recv(%d):%s\n",n,buff);
            send(c,"ok",2,0);
            close(c);
        }
}

saddr :存放的是服务器端的ip地址和端口
int len = sizeof(caddr); // caddr:那个客户端成功连接。那么caddr存放的就该客户端主机的ip地址和端口号。

客户端

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
       int sockfd = socket(AF_INET,SOCK_STREAM,0);
       if(sockfd == -1)
      {
             exit(1); 
       }
       //客户端可以不用设置端口和ip地址,客户端去连接服务器,不需要知道自己的ip和端口,只需要知道服务器的就行。
       struct sockaddr_in saddr;
       memset(&saddr,0,sizeof(saddr));
       saddr.sin_family = AF_INET;
       saddr.sin_port = htons(6000);
       saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
       

       //连接服务器
       int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
       if(res == -1)
       {
               printf("connect failed\n");
                close(sockfd);
                exit(1);   
       
       }

       printf("input:\n");
       char buff[128] = {0};
       fgets(buff,128,stdin);
       send(sockfd ,buff,strlen(buff)-1,0);
       memset(buff,0,128);
       recv(sockfd,buff,128,0);
       printf("recv:%s\n",buff);

       close(sockfd);
       exit(0);

 }

先启动服务器端
在启动客户端
最后发数据
请添加图片描述

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于TCP/IP网络编程的实验主要是通过使用TCP/IP协议栈进行网络通信的编程实践。在实验中,我们可以利用编程语言(如C、C++、Java等)中的相关库和API来实现网络通信的功能。 在实验中,我们可以学习和掌握以下几个方面的内容: 1. 建立连接:使用TCP协议建立客户端与服务器之间的连接。通过使用socket编程接口,我们可以创建一个套接字,并使用该套接字连接到服务器的特定端口。 2. 传输数据:通过TCP连接,在客户端和服务器之间传输数据。我们可以使用socket编程接口中的send和recv函数,在连接建立后,通过发送和接收数据来实现双向通信。 3. 错误处理:网络编程中,错误处理是至关重要的一部分。在实验中,我们需要学习如何处理连接错误、数据传输错误等网络相关的错误,并采取相应的措施来解决这些问题,确保程序的正常工作。 4. 多线程编程:在实验中,我们可以尝试使用多线程编程技术来处理多个客户端同时连接的情况。通过使用多线程,我们可以实现并发处理多个客户端请求的功能,提高程序的整体性能。 通过进行基于TCP/IP网络编程的实验,我们可以深入了解计算机网络通信的原理和相关技术,提高我们的编程能力和网络调试能力。这种实践能够让我们更好地理解和应用网络编程的知识,为今后的网络开发和应用提供有力的支持。 ### 回答2: 基于TCP/IP网络编程的实验是一种通过使用TCP/IP协议栈来实现网络通信的实验。这种实验方法可以帮助学习者深入了解网络编程的原理和技术,并实践如何使用TCP/IP来建立、管理和维护网络连接。 在实验中, 学习者首先需要了解TCP/IP协议的结构和工作原理。TCP/IP协议栈由多个层次构成,包括物理层、数据链路层、网络层、传输层和应用层。每一层有不同的功能和责任,并且通过封装和解封装数据来实现网络通信。 实验中的一个常见任务是建立一个TCP连接。学习者需要编写客户端和服务器端的代码来启动TCP连接,并通过发送和接收数据的方式进行通信。通过此实验,学习者能够学习到TCP连接的建立过程、TCP的可靠性传输和流量控制机制等相关知识。 另一个常见的实验任务是使用UDP协议进行数据传输。UDP是一种无连接和不可靠的传输协议,适用于需要高速传输和实时响应的应用场景。学习者需要编写代码来实现UDP的数据收发功能,并了解UDP的特性。 在实验中,学习者还可以学习到网络套接字编程的相关知识。通过编写基于套接字的代码,可以实现对网络连接的控制和管理,例如建立连接、监听连接请求、处理数据传输等。 通过基于TCP/IP网络编程的实验,学习者可以更加深入地理解网络通信的原理和技术,掌握网络编程的相关技能,并在实践中锻炼解决问题的能力。这样的实验不仅对于网络工程、计算机科学等专业的学生来说是非常重要的,对于对网络通信感兴趣的爱好者也是非常有帮助的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值