網絡駭客入門之UDP編程
本文列出了在LINUX系統下使用C語言進行UDP收發操作的常用函數和用法
註意:
創建套接字時,系統會分配一個臨時端口,默認主動發起服務請求,作為服務器時可修改為被動
發送數據時,不需要用bind綁定端口(當然綁定也可以)
接收數據時,如果不想知道發送者的信息(如:IP地址,端口等),可以不創建發送者結構體,然後recvfrom的後兩個參數寫NULL
因為網絡上的字節序是大端格式(低地址存高字節),所以在發送數據和顯示接收的數據時要用htonl/htons和ntohl/ntohs轉換(即host to net long/short和net to host long/short)
如果是IP地址,常用inet_pton/inet_ntop
inet_pton(AF_INET, "10.220.4.100", &dst_addr.sin_addr);
char cli_ip[16] = "";
inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, sizeof(cli_ip));
當然inet_addr("10.220.4.100")也可以,不過年紀大了,不中用了。
1發送數據
1.1.頭文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
main()函數
1.2創建套接字
int sockedfd = 0;
sockedfd = socket(AF_INET,SOCK_DGRAM,0);//創建UDP套接字
if(sockedfd < 0)
{
perror("socket");
exit(-1);
}
1.3發送消息緩沖區
char buf[100]="hello";
1.4填充發送結構體
struct sockaddr_in dst_addr;//目的結構體
bzero(&dst_addr,sizeof(dst_addr));
dst_addr.sin_family = AF_INET;//協議類型
dst_addr.sin_port = htons(8080);//目的端口
inet_pton(AF_INET, "10.220.4.100", &dst_addr.sin_addr); //目的IP地址
1.5發送數據,返回發送的字節數
int len = sendto(sockedfd,buf,strlen(buf),0,(struct sockaddr *)&dst_addr,sizeof(dst_addr));
printf("len = ==%d\n",len);
1.6
關閉套接字
close(sockedfd);
2接收數據
2.1創建套接字
int sockedfd = 0;
sockedfd = socket(AF_INET,SOCK_DGRAM,0);//創建UDP套接字
if(sockedfd < 0)
{
perror("socket");
exit(-1);
}
//填充接收結構體
struct sockaddr_in my_addr;//接收結構體
bzero(&my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;//協議類型
my_addr.sin_port = htons(8080);//接收端口
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接收IP地址設為任意IP
int err;
//綁定接收端口,便於其它機器訪問
err = bind(sockedfd,(struct sockaddr*)&my_addr,sizeof(my_addr));
if(err != 0)
{
perror("bind");
close(sockedfd);
exit(-1);
}
//定義接收緩沖區
char buf[100]="";
//創建發送者結構體,用於儲存發送者信息
struct sockaddr_in src_addr;
bzero(&src_addr,sizeof(src_addr));
//發送者結構體的大小
int len=sizeof(src_addr);
//從套接字接收數據
recvfrom(sockedfd,buf,sizeof(buf),0,(struct sockaddr*)&src_addr,&len);
//顯示發送端口
printf("port == %d\n",ntohs(src_addr.sin_port));
關閉套接字
close(sockedfd);
下面介紹一下類似於迅雷等下載器的tftp協議
TFTP即簡單文本傳輸協議,工作在應用層,基於UDP,不進行用戶認證
只要往69號端口按固定的消息格式發送一條文件請求,另一邊的服務器就會把請求的文件發送過來
消息格式:操作碼+文件名+0+傳輸模式+0其中操作碼為2字節(1讀,2寫,3數據,4確認,5錯誤)
數據包格式為操作碼3(2B)+編號(2B)+數據,收到數據包後要發送確認包 操作碼4(2B)+塊編號
如果數據包小於516字節則說明接收完畢。
具體程序如下:
前面的步驟都一樣了
char sendbuf[512]="";
int len = sprintf(sendbuf,"%c%c%s%c%s%c",0,1,“hello.txt”,0,"octet",0);//"octet"為二進制模式,“netascii”為文本模式
sendto(sockfd,sendbuf,len,0,(struct sockaddr*)&dest_addr,sizeof(dest_addr));
發送完了立刻進行接收
do{
//接收服務器發送的內容
len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);
cmd = recv_buf[1];
if( cmd == 3 )//是否為數據包
{
//包編號是否和上次相等
if( (unsigned short)(p_num+1) == ntohs(*(unsigned short*)(recv_buf+2) ))
{
write(fd, recv_buf+4, len-4);
p_num = ntohs(*(unsigned short*)(recv_buf+2));
printf("recv:%d\n", p_num);//十進制方式打印包編號
}
recv_buf[1] = 4;//操作碼+1從數據包變為確認包
sendto(sockfd, recv_buf, 4, 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
}
else if( cmd == 5 ) //是否為錯誤應答
{
close(fd);
close(sockfd);
unlink(argv[2]);
printf("error:%s\n", recv_buf+4);
return 0;
}
}while(len == 516); //如果收到的數據小於516則認為出錯
close(fd);
close(sockfd);
網絡駭客入門之UDP編程