第十三章學習筆記
知識點歸納
TCP/IP協議
-
TCP/IP 是互聯網的基礎。TCP代表傳輸控制協議。IP代表互聯網協議。目前有兩個版本的IP,即IPv4和IPv6。IPv4使用32位地址,IPv6則使用128位地址。
-
本節圍繞IPv4進行討論,它仍然是目前使用最多的IP版本。
-
TCP/IP的組織結構分為幾個層級,通常稱為TCP/IP堆棧。
-
頂層是使用TCP/IP的應用程序。
-
用于登錄到遠程主機的ssh、用于交換電子郵件的郵件、用于Web頁面的http等應用程序需要可靠的數據傳輸。通常,這類應用程序在傳輸層使用TCP。
-
另一方面有些應用程序,例如用于查詢其他主機的ping命令,則不需要可靠性。這類應用程序可以在傳輸層使用UDP來提高效率。
-
主機:主機是支持TCP/IP協議的計算機或設備。每個主機由一個32位的IP地址來標識。
-
路由器是接收和轉發數據包的特殊IP主機。如果有的話, 一個IP數據包可能會經過許多路由器,或者跳躍到達某個目的地。
UDP
- UDP是用戶數據報協議。

TCP
TCP(傳輸控制協議)是一種面向連接的協議。

應用程序=(主機IP,協議,端口號)
TCP/IP網絡中的數據流
應用程序層的數據被傳遞到傳輸層,傳輸層給數據添加一個TCP或UDP報頭來標識使用的傳輸協議。合并后的數據被傳遞到IP網絡層,添加一個包含IP地址的IP報頭來標識發送和接收主機。然后,合并后的數據再被傳遞到網絡鏈路層,網絡鏈路層將數據分成多個幀,并添加發送和接收網絡的地址,用于在物理網絡之間傳輸:IP地址到網絡地址的映射由地址解析協議(ARP)執行。
在接收端,數據編碼過程是相反的。 每一層通過剝離數據頭來解包接收到的數據,重新組裝數據并將數據傳遞到上層。發送主機上的應用程序原始數據最終會被傳遞到接收主機上的相應應用程序。
問題與解決思路
原始套接字的作用是什么?
原始套接字,指在傳輸層下面使用的套接字。流式套接字和數據報套接字這兩種套接字工作在傳輸層,主要為應用層的應用程序提供服務,并且在接收和發送時只能操作數據部分,而不能對IP首部或TCP和UDP首部進行操作,通常把這兩種套接字稱為標準套接字。
但是,如果我們開發的是更底層的應用,比如發送一個自定義的IP包、UDP包、TCP包或ICMP包,捕獲所有經過本機網卡的數據包,偽裝本機的IP,想要操作IP首部或傳輸層協議首部,等等,這些功能對于這兩種套接字就無能為力了。這些功能需要使用另一種套接字來實現,這種套接字叫作原始套接字,功能更強大,更底層。
原始套接字可以在鏈路層收發數據幀。
原始套接字可以自動組裝數據包(偽裝本地IP和本地MAC),可以接收本機網卡上所有的數據幀(數據包)。另外,必須在管理員權限下才能使用原始套接字。
原始套接字直接置“根”于操作系統網絡核心(Network Core),而SOCK_STREAM、SOCK_DGRAM則“懸浮”于TCP和UDP協議的外圍,如下圖所示:
流式套接字只能收發TCP協議的數據,數據報套接字只能收發UDP協議的數據,原始套接字可以收發沒經過內核協議棧的數據包。
實踐內容
udpserver.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#define SERVER_PORT 9999
#define BUFF_LEN 1024
void handle_udp_msg(int fd)
{
char buf[BUFF_LEN]; //接收緩沖區,1024字節
socklen_t len;
int count;
struct sockaddr_in clent_addr; //clent_addr用于記錄發送方的地址信息
while(1)
{
memset(buf, 0, BUFF_LEN);
len = sizeof(clent_addr);
count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, &len); //recvfrom是擁塞函數,沒有數據就一直擁塞
if(count == -1)
{
printf("recieve data fail!\n");
return;
}
printf("client:%s\n",buf); //打印client發過來的信息
memset(buf, 0, BUFF_LEN);
sprintf(buf, "I have recieved %d bytes data!\n", count); //回復client
printf("server:%s\n",buf); //打印自己發送的信息給
sendto(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, len); //發送信息給client,注意使用了clent_addr結構體指針
}
}
/*
server:
socket-->bind-->recvfrom-->sendto-->close
*/
int main(int argc, char* argv[])
{
int server_fd, ret;
struct sockaddr_in ser_addr;
server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP
if(server_fd < 0)
{
printf("create socket fail!\n");
return -1;
}
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要進行網絡序轉換,INADDR_ANY:本地地址
ser_addr.sin_port = htons(SERVER_PORT); //端口號,需要網絡序轉換
ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
if(ret < 0)
{
printf("socket bind fail!\n");
return -1;
}
handle_udp_msg(server_fd); //處理接收到的數據
close(server_fd);
return 0;
}
udpclient.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define SERVER_PORT 9999
#define BUFF_LEN 512
#define SERVER_IP "127.0.0.1"
void udp_msg_sender(int fd, struct sockaddr* dst)
{
socklen_t len;
struct sockaddr_in src;
while(1)
{
char buf[BUFF_LEN] = "TEST UDP MSG!\n";
len = sizeof(*dst);
printf("client:%s\n",buf); //打印自己發送的信息
sendto(fd, buf, BUFF_LEN, 0, dst, len);
memset(buf, 0, BUFF_LEN);
recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&src, &len); //接收來自server的信息
printf("server:%s\n",buf);
sleep(1); //一秒發送一次消息
}
}
/*
client:
socket-->sendto-->revcfrom-->close
*/
int main(int argc, char* argv[])
{
int client_fd;
struct sockaddr_in ser_addr;
client_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(client_fd < 0)
{
printf("create socket fail!\n");
return -1;
}
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
//ser_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //注意網絡序轉換
ser_addr.sin_port = htons(SERVER_PORT); //注意網絡序轉換
udp_msg_sender(client_fd, (struct sockaddr*)&ser_addr);
close(client_fd);
return 0;
}
posted on 2022-11-13 20:18 20201321周慧琳 閱讀(25) 評論(0) 收藏 舉報
浙公網安備 33010602011771號