20211316郭佳昊 《信息安全系统设计与实现(上)》 第十一周学习总结 第十三章TCP/IP和网络编程

发布时间 2023-11-26 12:26:40作者: 20211316郭佳昊

一、任务要求

[ 1 ] 知识点归纳以及自己最有收获的内容,选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容 (4分)
我在学****知识点,请你以苏格拉底的方式对我进行提问,一次一个问题

核心是要求GPT:请你以苏格拉底的方式对我进行提问

然后GPT就会给你提问,如果不知道问题的答案,可以反问AI:你的理解(回答)是什么?

如果你觉得差不多了,可以先问问GPT:针对我XXX知识点,我理解了吗?

GPT会给出它的判断,如果你也觉得自己想清楚了,可以最后问GPT:我的回答结束了,请对我的回答进行评价总结,让它帮你总结一下。

[ 2 ] 问题与解o决思路,遇到问题最先使用chatgpt等AI工具解决,并提供过程截图(3分)

[ 3 ] 实践过程截图,代码链接(2分)

[ 4 ] 其他(知识的结构化,知识的完整性等,提交markdown文档,使用openeuler系统等)(1分)

二、知识点总结

TCP/IP协议

TCP/IP堆栈
image

  • 顶层是使用TCP/IP的应用程序。用于登录到远程主机的ssh、用于交换电子邮件的mail、用于Web界面的http等应用程序需要可靠的数据传输。
  • 不需要可靠性的应用程序可以在传输层使用UDP来提高效率。
  • 传输层负责以包的形式向IP 主机发送/接收来自IP 主机的应用程序数据。进程与主机之间的传输层或其上方的数据传输只是逻辑传输。实际数据传输发生在互联网(IP)和链路层,这些层将数据包分成数据帧,以便在物理网络之间传输。

IP主机和IP地址

  • 主机是支持TCP/IP协议的计算机或设备,每个主机由一个32位的IP地址来表示。通常使用点记法。
  • IP地址分为networkID字段和hostID字段

IP数据包格式

image

路由器

TCP/IP网络拓扑结果:
image
每个IP包在IP包头中都有一个8位生存时间(TTL),最大值位255,每经过一个路由器,TTL减一,TTL减小到0,包会被丢弃,,如此可以防止数据包在IP网络中无限循环。

UDP和TCP

  • UDP:在IP上运行,用于发送/接收数据报。与IP 类似,UDP不能保证可靠性,但是快速高效。它可用于可靠性不重要的情况例如,用户可以使用ping命令探测目标主机
  • TCP:TCP(传输控制协议)是一种面向连接的协议,用于发送/接收数据流。TCP也可在IP上运行,但它保证了可靠的数据传输。通常,UDP类似于发送邮件的USPS,而TCP类似于电话连接。

端口编号

在各主机中,多个应用程序可同时使用TCP/UDP,每个应用程序可由三个组成部分唯一表示:应用程序=(主机IP, 协议, 端口号),协议是TCP/UDP,端口号是分配给应用程序的唯一无符号短整数。
使用TCP的常见应用程序及其端口号:
image

网络和主机字节序

  • 大端:高位字节存入低地址,低位字节存入高地址
  • 小端:低位字节存入低地址,高位字节存入高地址

TCP/IP网络中的数据流

image

套接字编程

套接字地址

struct sockaddr_in {
    sa_family_t sin_family; 
    in_port_t sin_port; 
    struct in_addr sin_addr;
};
struct in_addr {
    uint32_t s_addr;
}

套接字API

1. int套接字
int udp_sock = socket(AF_INET, SOCK_DGRAM, 0); //将会创建一个用于发送/接收UDP数据报的套接字。
int tcp_sock = socket(AF_INET, SOCK_STREAM, 0); //将会创建一个用于发送/接收数据流的面向连接的TCP套接
字c
2.int bind
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)

bind()系统调用将addr指定的地址分配给文件描述符sockfd所引用的套接字addrlen 指定addr所指向地址结构的大小(以字节为单位)。对于用于联系其他UDP服务器主机的UDP套接字,必须绑定到客户机地址,允许服务器发回应答。对于用于接收客户机连接的TCP套接字,必须先将其绑定到服务器主机地址。

3.UDP套接字

UDP套接字使用sendto()/recvfrom()来发送/接受数据报

4.TCP套接字

在创建套接字并将其绑定到服务器地址之后,TCP服务器使用listen()和acccpt()来接 收来自客户机的连接
int Iistcn(int sockfd, int backlog);
listen()将sockfd引用的套接字标记为将用于接收连入连接的套接字。backlog参数定义了等 待连接的最大队列长度。
int accept(int sockfd, struct sockaddr *addr, sockien_t *addrlen);
accept()系统调用与基于连接的套接字一起使用。它提取等待连接队列上的第一个连接请求 用于监听套接字sockfd,创建一个新的连接套接字,并返回一个引用该套接字的新文件描 述符,与客户机主机连接。在执行accept()系统调用时,TCP服务器阻塞,直到客户机通过 coimectO建立连接。
int connect(int sockfd, const struct sockaddr *addr, socklen t addrlen);
connect()系统调用将文件描述符sockfd引用的套接字连接到addr指定的地址,addrlen参数 指定addr的大小。addr中的地址格式由套接字sockfd的地址空间决定。
如果套接字sockfd是SOCK_DGRAM类型,即UDP套接字,addr是发送数据报的默 认地址,也是接收数据报的唯一地址。这会限制UDP套接字与特定UDP主机的通信,但实际上很少使用。所以对于UDP套接字来说,连接是可选的或不必要的。如果套接字是 SOCK_STREAM类型,即TCP套接字。

三、苏格拉底挑战

image
image
image
image

四、实践

UDP回显服务器——客户机程序

服务器

#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#define BUFLEN256
#define PORT1234

char line[BUFLEN];
struct sockaddr_in me, client;
int sock,rlen,clen = sizeof(client);
int main()
{
  printf("1. create a UDP socket\n");
  sock = socket(AF_INET,SOCK DGRAM,IPPROTO UDP);

  printf("2.fill me with server address and port number\n");
  memset((char *)&me,0,sizeof(me));
  me.sin family = AF INET;
  me.sin port = htons(PORT);
  me.sin_addr.s_addr = htonl(INADDR ANY);

  printf("3.bind socket to server IP and portln");
  bind(sock, (struct sockaddr*)&me, sizeof(me));

  printf("4.wait for datagram\n");
  while(1){
    memset(line,0,BUFLEN);
    printf("UDP server: waiting for datagram\n");
    rlen=recvfrom(sock,line,BUFLEN,0(struct sockaddr *)&client,&clen);
    printf("received a datagram from [host:port] =[s:d]\n"inet ntoa(client.sin addr),ntohs(client.sin port));
    printf("rlen=%d: ine=s\n",rlen,line);printf("send reply\n");
    sendto(sock,line,rlen,0,(struct sockaddr*)&client,clen);
  }
}

客户机

#include<stdio.h>
#include<stalib.h>
#include<string.h>
#include<sys/socket.h>
#include <netinet/ip.h>
#define SERVER_HOST"127.0.0.1"
#define SERVER PORT1234

#define BUFLEN 256

char line[BUFLEN];
struct sockaddr in server;
int sock,rlen, slen=sizeof(server);
int main()
{
  printf("1.create a UDP socket\n");
  sock = socket(AF_INET,SOCK DGRAM, IPPROTO UDP);

  printf("2.fill in server address and port number\n");
  memset((char *) &server,0,sizeof(server));
  other.sin family = AF INET;
  other.sin port = htons(SERVER PORT);
  inet aton(SERVER HOST,&server.sin addr);

  while(1){
    printf("Enter a line : ");
    fgets(line,BUFLEN,stdin);
    line[strlen(line)-1] = 0;
    printf("send line to server\n");
    gendto(sock,line,strlen(line),0,(struct sockaddr *)&server,slen);
    memset(line,0,BUFLEN);
    printf("try to receive a line from server\n");
    rlen=recvfrom(sock,line,BUFLEN,0,(struct sockaddr*)&server,&slen);
    printf("rlen=d: line=%s\n",rlen, line);
  }
}

TCP回显服务器——客户机程序

服务器:

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

#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 1234 

struct sockaddr_in server_addr, client_addr;
int mysock, csock;

void server_init() {
    printf("================ server init =================\n");

    printf("1 : create a TCP socket\n");
    mysock = socket(AF_INET, SOCK_STREAM, 0);
    if (mysock < 0) {
        perror("socket call failed");
        exit(1);
    }

    printf("2 : fill server_addr with server's IP and PORT#\n");
    memset((char*)&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    server_addr.sin_port = htons(SERVER_PORT);

    printf("3 : bind socket to server address\n");
    int r = bind(mysock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (r < 0) {
        perror("bind failed");
        exit(3);
    }

    printf("hostname = %s port = %d\n", SERVER_HOST, SERVER_PORT);
    printf("4 : server is listening ....\n");
    
    listen(mysock, 5); // Queue length = 5

    printf("================== init done ===============\n");
}

int main() {
    int n;
    char line[MAX];

    server_init();

    while (1) {
        printf("server: accepting new connection ....\n");
        socklen_t len = sizeof(client_addr);
        csock = accept(mysock, (struct sockaddr*)&client_addr, &len);
        if (csock < 0) {
            perror("server: accept error");
            exit(1);
        }

        printf("server: accepted a client connection from\n");
        printf("Client: IP=%s port=%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

        while (1) {
            n = recv(csock, line, MAX, 0);
            if (n <= 0) {
                printf("server: client closed the connection, server loops\n");
                close(csock);
                break;
            }

            printf("server: received n=%d bytes; line=%s\n", n, line);

            n = send(csock, line, n, 0);
            printf("server: sent n=%d bytes; echo=%s\n", n, line);
        }
    }

    return 0;
}

客户机:

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

#define MAX 256
#define SERVER_HOST "localhost"
#define SERVER_PORT 1234

struct sockaddr_in server_addr;
int sock, r;

int client_init() {
    printf("================ client init =================\n");

    printf("1 : create a TCP socket\n");
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket call failed");
        exit(1);
    }

    printf("2 : fill server_addr with server's IP and PORT#\n");
    memset((char*)&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // Use localhost
    server_addr.sin_port = htons(SERVER_PORT);

    printf("3 : connecting to server ...\n");
    r = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (r < 0) {
        perror("connect failed");
        exit(3);
    }

    printf("4 : connected OK to\n");
    printf("-----------------------------\n");
    printf("Server hostname=%s PORT=%d\n", SERVER_HOST, SERVER_PORT);
    printf("-----------------------------\n");
    printf("================ init done ================\n");
}

int main() {
    int n;
    char line[MAX], ans[MAX];
    client_init();
    printf("********** processing loop ************\n");

    while (1) {
        printf("input a line : ");
        bzero(line, MAX); 
        fgets(line, MAX, stdin); 
        line[strlen(line) - 1] = '\0'; 

        if (line[0] == '\0') 
            exit(0);

        n = write(sock, line, MAX);
        printf("client: wrote n=%d bytes; line=%s\n", n, line);

        n = read(sock, ans, MAX);
        printf("client: read n=%d bytes; echo=%s\n", n, ans);
    }

    return 0;
}