学习笔记11

20211301 学习笔记11

教材知识点总结

TCP/IP协议

  • TCP:代表传输控制协议

  • IP:代表互联网协议

  • IPv4:32位

  • IPv6:64位

  • 堆栈

  • 顶层:应用程序,用于登录远程主机ssh、用于交换电子邮件、用于web页面的http等应用程序需要可靠的数据传输

  • 网络中的数据流路径:

IP主机和IP地址

  • 主机是支持TCP/IP协议的计算机或设备,每个主机由一个32位的IP地址来标识

  • 主机也可以用主机名来表示,如dnsl.eec.wsuedu

  • 主机名就等同于IP 地址,因为给定其中一个,我们可以通过DNS(域名系统)(RFC1341987:RFC 10351987)服务器找到另一个

  • IP地址分为两部分,即NetworkID 字段和HostID字段

  • 发往IP地址的数据包首先被发送到具有相同networkID的路由器

  • 每个主机都有一个本地主机名localhost,默认IP地址为127.0.0.1本地主机的链路层是一个回送虚拟设备,它将每个数据包路由回同一个localhost。这个特性可以让我们在同一台计算机上运行TCP/IP应用程序而不需要实际连接到互联网

IP协议

  • IP 协议用于在IP 主机之间发送/接收数据包。IP 尽最大努力运行。IP 主机只向接收主机发送数据包,但它不能保证数据包会被发送到它们的目的地,也不能保证按顺序发送。这意味着 IP 并非可靠的协议。

IP数据包格式

  • IP 数据包由IP头、发送方IP 地址和接收方P 地址以及数据组成。每个IP 数据的大小最大为64KB。IP 头包含有关数据包的更多信息,例如数据包的总长度、数据包使用TCP还是UDP、生存时间(TTL)计数、错误检测的校验和

路由器

  • IP 主机之间可能相距很远。通常不可能从一个主机直接向另一个主机发送数据包。

  • 了TCP/IP 网络的拓扑结构:

  • 每个IP包在IP报头中都有一个8位生存时间(TTL)计数,其最大值为255。在每个路由器上,TTL会减小1。如果 TTL减小到0,而包仍然没有到达目的地,则会直接丢弃它。这可以防止任何数据包在IP网络中无限循环

UDP

  • UDP(用户数据报协议)(RFC 768 1980: Comer1988)在IP上运行用于发送/接收数据报。与IP类似,UDP不能保证可靠性,但是快速高效。它可用于可靠性不重要的情况

  • ping主机名或pingP地址:ping是一个向目标主机发送带时间戳UDP包的应用程序。接收到一个pinging数据包后,目标主机将带有时间戳的UDP 包回送给发送者,让发送者可以计算和显示往返时间

TCP

  • TCP(传输控制协议)是一种面向连接的协议,用于发送/接收数据流。TCP也可在IP上运行,但它保证了可靠的数据传输。通常,UDP类似于发送邮件的USPS,而TCP类似于电话连接。

端口编号

  • 应用程序=(主机IP,协议,端口号)

网络和主机字节序

  • 计算机可以使用大端字节序,也可以使用小端字节序。在互联网上,数据始终按网络序排列,这是大端。在小端机器上,例如基于Intelx86的PC,htons、htonl0、ntohs0ntoh10等库函数,可在主机序和网络序之间转换数据。

  • 必须先通过 htons(1234)把它转换成网络序,才能使用。相反,从互联网收到的端口号必须先通过ntohs(port)转换为主机序。

TCP/IP网络中的数据流

网络编程

  • 所有linux都支持

  • 通过下面几种方法访问

    • 服务器上的用户账户
    • 单独PC或笔记本电脑
  • 服务器-客户机计算模型

    • 首先在服务器主机上运行服务器进程,然后从客户机主机运行客户机

套接字编程

  • 在网络编程中,TCP/IP 的用户界面是通过一系列C语言库函数和系统调用来实现的这些函数和系统调用统称为套接字API((Rago1993;Stevens等2004)。为了使用套接字API,我们需要套接字地址结构,它用于标识服务器和客户机。netdb.h和 sys/socket.h中有套接字地址结构的定义。

  • 服务器必须创建一个套接字,并将其与包含服务器IP 地址和端口号的套接字地址绑定。它可以使用一个固定端口号,或者让操作系统内核选择一个端口号(如果sin port为0)。为了与服务器通信,客户机必须创建一个套接字。对于UPD套接字,可以将套接字绑定到服务器地址。如果套接字没有绑定到任何特定的服务器,那么它必须在后续的 sendto()recvfrom0调用中提供一个含服务器IP和端口号的套接字地址。下面给出了scket0系统调用,它创建一个套接字并返回一个文件描述符

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

  • 。服务器在默认本地主机上运行(IP = 127.0.0.1)使用固定端号1234。这可以简化程序代码。读者可以在同一台计算机上以不同的xterms测试运行服务器和客户机程序。

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

  • 设服务器和客户机都在同一台计算机上运行,服务器端口号硬编码为1234

主机名和IP地址

  • 假设服务器和客户机在同一台计算机上运行,并且服务器使用固定端口号

代码实现

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

#define BUFLEN 256
#define PORT 1234

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 port\n");
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: line=%s\n", rlen, line);
        printf("send reply\n");
        sendto(sock, line, rlen, 0, (struct sockaddr*)&client, clen);
    }

    return 0;
}
  • client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>  // Added inclusion of arpa/inet.h for inet_aton function
#define SERVER_HOST "127.0.0.1"  // Default server IP: localhost
#define SERVER_PORT 1234  // Fixed server port number
#define BUFLEN 256  // Max length of buffer

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));
    server.sin_family = AF_INET;
    server.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';  // Fixed newline character removal
        printf("send line to server\n");
        sendto(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);
    }

    return 0;
}

  • 13.15 server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

#define MAX 256
#define SERVER_PORT 1234

int mysock, csock;
struct sockaddr_in server_addr, client_addr;

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

    printf("2 : fill server_addr with host IP and PORT# info\n");
    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) {
        printf("bind failed\n");
        exit(3);
    }

    printf("port = %d\n", SERVER_PORT);
    printf("4 : server is listening ....\n");
    listen(mysock, 5);

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

int main()
{
    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) {
            printf("server: accept error\n");
            exit(1);
        }

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

        while (1) {
            int n = read(csock, line, MAX);
            if (n <= 0) {
                printf("server: client died, server loops\n");
                close(csock);
                break;
            }

            line[n] = '\0'; // Ensure null-terminated string

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

            n = write(csock, line, n);
            printf("server: wrote n=%d bytes; ECHO=%s\n", n, line);
            printf("server: ready for next request\n");
        }
    }
}

  • client
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>

#define MAX 256
#define SERVER_HOS "localhost"
#define SERVER_PORT 1234
struct sockaddr_in server_addr;
int sock,r;
int client_init()
{
printf("======= clinet init ==========\n");
printf("1 : create a TCP socket\n");
sock = socket(AF_INET, SOCK_STREAM,0);
if (sock<0){
printf("socket call failed\n"); exit(1);
}
printf("2 : fill server_addr with server's IP and PORT#\n");
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);// localhost
server_addr.sin_port = htons(SERVER_PORT); // server port number
printf("3 : connecting to server ....\n");
r = connect(sock,(struct sockaddr*)&server_addr, sizeof(server_addr));
if(r<0){
printf("connect failed\n");exit(3);
}
printf("4 : connected OK to\n");
printf("--------------------------------------------\n");
printf("Server hostname=%s PORT=d\n",SERVER_HOS,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);// Send line to server
n = write(sock,line, MAX);
printf("client: wrote n=%d bytes; line=%s\n",n,line);// Read a line from sock and show it
n = read(sock, ans, MAX);
printf("client: read n=%d bytes; echo=%s\n",n,ans);
}
}

苏格拉底挑战

  • 大端小端


  • 套接字编程





posted @ 2023-11-24 20:42  20211301郑润芃  阅读(2)  评论(0编辑  收藏  举报