学习笔记11
第一部分:教材知识总结
学习目标
通过本章的学习,了解TCP/IP协议及其应用,包括...
- TCP/IP协议栈
- IP地址、主机名、DNS、IP数据包和路由器
- TCP/IP协议簇中的UDP和TCP协议、端口号和数据流
- 套接字及通过简单编程加深理解
- Web和CGI编程,HTTPD服务器,HTTP编程模型,Web服务器的配置和运行
网络编程的本质
网络编程是使用IP地址、域名和端口连接到另一台计算机上对应的程序,按照规定的协议交换数据。它主要涉及两个设备之间的数据交换,在计算机网络中通常指计算机之间的数据传递。
TCP/IP协议
TCP/IP是能够在多个不同网络间实现信息传输的协议簇,包括FTP、SMTP、TCP、UDP、IP等协议。TCP代表传输控制协议,IP代表互联网协议。IPv4使用32位地址,IPv6使用128位地址。
IP主机和IP地址
每个主机都有一个本地主机名localhost,默认 IP地址为 127.0.0.1。
本地主机的链路层是一个回送虚拟设备,它将每个数据包路由回同一个localhost。这个特性可以让我们在同一台计算机上运行TCP/IP 应用程序,而不需要实际连接到互联网。
IP地址分为两部分,即 NetworkID 字段和HostID字段。根据划分,IP 地址分为A~E类。
IP协议
IP协议用于在 IP主机之间发送/接收数据包。IP尽最大努力运行。IP 主机只向接收主机发送数据包,但它不能保证数据包会被发送到它们的目的地,也不能保证按顺序发送。这意味着IP 并非可靠的协议。
路由器
是接收和转发数据包的特殊IP主机。一个IP数据包可能会经过许多路由器,或者跳跃到达某个目的地。每个IP包在IP报头中都有一个8位生存时间(TTL)计数,其最大值为255。
UDP
UDP(用户数据报协议)(RFC768 1980;Comer 1988)在IP上运行,用于发送/接收数据报。与IP类似,UDP不能保证可靠性,但是快速高效。
TCP
TCP(传输控制协议)是一种面向连接的协议,用于发送/接收数据流。TCP也可在IP 上运行,但它保证了可靠的数据传输。
端口编号
端口号是分配给应用程序的唯一无符号短整数。要想使用UDP或TCP,应用程序(进程)必须先选择或获取一个端口号。前1024个端口号已被预留。其他端口号可供一般使用。应用程序可以选择一个可用端口号,也可以让操作系统内核分配端口号。
端口号的范围从0到65535。
使用 netstat -nao 可以查看系统中端口的活动情况。
编程练习1:使用C语言实现简单UDP传输
客户端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#define MAXBUF 256
int main(int argc, char const *argv[])
{
int s = 0;
int n = 0;
int reuse = 1;
int port = 1987;
struct sockaddr_in srv;
char buf[MAXBUF] = {0};
/*解析参数*/
if (argc != 2)
{
printf("Usage:%s ServerIP\n", argv[0]);
return -1;
}
bzero(&srv, sizeof(srv));
srv.sin_family = PF_INET;
srv.sin_addr.s_addr = inet_addr(argv[1]);
srv.sin_port = htons(port);
/*创建 UDP 套节字*/
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s<0){
perror("socket");
return -1;
}
while(1){
memset(buf, 0, MAXBUF);
/*读取用户输入到buf中*/
fgets(buf, MAXBUF, stdin);
/*通过套节字 s 向服务器发送数据*/
if ((n = sendto(s, buf, strlen(buf), 0, (struct sockaddr *) &srv, sizeof(struct sockaddr))) < 0)
{
perror("sendto");
return -1;
}else{
printf("send to %s(port=%d) len %d:%s\n", argv[1], port, n, buf);
}
}
}
服务端代码
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <netinet/ip.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);//use localhost 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); }}
编程练习2:使用C语言实现简单TCP传输
服务器代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX 256
#define SERVER_PORT 1234
struct sockaddr_in server_addr, client_addr;
int mysock, csock; // socket descriptors
int r, len, n; // help variables
int server_init()
{
printf("================== server init ======================\n");
// create a TCP socket by socket() syscall
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");
// initialize the server_addr structure
server_addr.sin_family = AF_INET; // for TCP/IP
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // This HOST IP
server_addr.sin_port = htons(SERVER_PORT); // port number 1234
printf("3 : bind socket to server address\n");
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); // queue length = 5
printf("=================== init done =======================\n");
}
int main()
{
char line[MAX];
server_init();
while (1)
{
// Try to accept a client connection as descriptor newsock
printf("server: accepting new connection ....\n");
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(client_addr.sin_addr),
ntohs(client_addr.sin_port));
printf("-----------------------------------------------\n");
// Processing loop: client_sock <== data ==> client
while (1)
{
n = read(csock, line, MAX);
if (n == 0)
{
printf("server: client died, server loops\n");
close(csock);
break;
}
// show the line string
printf("server: read n=%d bytes; line=%s\n", n, line);
// echo line to client
n = write(csock, line, MAX);
printf("server: wrote n=%d bytes; ECHO=%s\n", n, line);
printf("server: ready for next request\n");
}
}
}
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX 256
#define SERVER_PORT 1234
#define SERVER_HOST "127.0.0.1" // Use the server's IP address
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)
{
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 = inet_addr(SERVER_HOST); // Server's IP
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 IP=%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); // zero out line[ ]
fgets(line, MAX, stdin); // get a line from stdin
line[strlen(line) - 1] = 0; // kill \n at the end
if (line[0] == 0) // exit if NULL line
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);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?