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);
}
}
苏格拉底挑战
-
大端小端
-
套接字编程