#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))

"|" 是按位或运算符,对整型数进行二进制按位取或运算。比如 0110 0011 | 0011 0101-------------------- = 0111 0111定义MakeWord(a, b) 的含义应该是将a b合成一个字(双字节),比如 MakeWord(0xaa, 0xbb) 结果应该是0xbbaa,a在低字节,转换成BYTE只留下一字节的内容,b也留下一字节并左移做高字节,通过按位或运算符将两者合并到一起。

高八位和低八位组合成一个word
是一个宏  
    
  #define   MAKEWORD(a,   b)             ((WORD)(((BYTE)(a))   |   ((WORD)((BYTE)(b)))   <<   8))
可以从字面理解就是生成一个WORD类型的值,第一个参数是高8位的值,第二个参数是低八位的值。
 
 

 

#include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <malloc.h> #define DOWNLOAD_PATH ".\\download\\" #define INT_SIZE sizeof(int) #define REQUEST_SIZE 35 #define PORT 7788 #define BUFFER_SIZE 1024 #define STOP_BYTE 0xFF #define VIDEO_LEN 60 // 视频总时长为60s int main() { /***初始化阶段***/ WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); int sock = 0; struct sockaddr_in serv_addr; char buffer[BUFFER_SIZE] = {0}; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Socket creation error"); return -1; } else printf("Client Create Socket Success. \n"); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); serv_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("Connection Failed"); return -1; } else printf("Client Connect Server Success. \n"); /*****************************************************************/ /********** 任务1: 如何向server循环请求连续的视频文件?**********/ /*****************************************************************/ // 发送下载请求 int bytes_sent = 0; unsigned char s_stop_byte = 0xFF; // 视频文件名 char req[REQUEST_SIZE] = "ocean-1080p-8000k-0.ts"; /******************************************************************/ /***************** 任务2:如何按顺序选择视频文件?*****************/ /******************************************************************/ bytes_sent = send(sock, req, REQUEST_SIZE, 0); if (bytes_sent < 0) printf("ERROR in send\n"); bytes_sent = send(sock, &s_stop_byte, sizeof(s_stop_byte), 0); if (bytes_sent < 0) printf("ERROR in send\n"); printf("send req: %s\n", req); // 接收文件的大小 int file_size; unsigned long file_size_buf; int bytes_recv = 0; bytes_recv = recv(sock, (char *)&file_size_buf, INT_SIZE, 0); file_size = ntohl(file_size_buf); printf("file_size %d \n", file_size); // 接收视频片段 char *video_segement = malloc(file_size); if (video_segement == NULL) { perror("malloc failed"); // 处理内存分配失败的情况,可能需要退出程序 return -1; } int recv_count = 0; while (recv_count < file_size) { /************************************************************************/ /***************** 任务3 : 如何使用buffer接收视频文件?*****************/ /************************************************************************/ } unsigned char r_stop_byte; if (recv(sock, &r_stop_byte, 1, 0) != 1 || r_stop_byte != STOP_BYTE) printf("ERROR in receiving stop byte 0x%02X \n", r_stop_byte); // 检查文件结束符 r_stop_byte = 'e'; // 重置 // 写入文件 char file_path[40] = DOWNLOAD_PATH; strcat(file_path, req); printf("file_path %s \n", file_path); FILE *fp = fopen(file_path, "wb"); // 以二进制模式打开文件,并返回文件指针 if (fp == NULL) { perror("fopen"); exit(EXIT_FAILURE); } fwrite(video_segement, 1, file_size, fp); /***数据接收完成阶段***/ // 释放内存 free(video_segement); video_segement = NULL; /*************************************************************************************/ /*********任务2(扩展):如何在视频流传输完成后,通知server结束视频传输?*************/ /*************************************************************************************/ /***结束阶段***/ closesocket(sock); WSACleanup(); return 0; }
04-01
熟悉ip地址的多种表现形式,理解ip地址,子网掩码,网络地址的涵义。 熟悉不同形式之间的转换,为后续实现arp协议做准备。 第一个任务,根据ip和子网掩码获得该ip的网络地址。完成函数: /*根据掩码获取ip地址对应的网络地址*/ uint32 get_netaddr(uint32 ip, uint32 mask); 第二个任务,就是做上述变换的逆变换,将unsigned int 的ip地址变为字符串的形式。完成函数: /*将数据表示的ip地址转为点10进制表示的字符串*/ char* ip2str(uint32 ip, char *ipstr) 第三个任务:完成字符串形式的ip地址,如“192.168.1.2”,转换成32位的ip地址,即转为unsigned int 符号网络字节顺序的32位无符号整数。 将地址设为无符号整数,比设为unsigned char[4]这样的数组,在进行比较操作,与掩码作运算时更方便。完成函数: /*将字符串表示的点10进制表示的ip地址转为数值表示*/ uint32 str2ip(char *ipstr) ; 相关知识 在本任务的src/data/cfg.txt配置文件展示了主机网卡的主要参数:即 ip地址是主机的标识号,mask子网掩码指定该主机属于哪个局域网,gate缺省网关,即负责本局域网主机与外网通信的所有ip包进出的转发。 同一网络的主机间可以进行广播通信,意味着它们之间的数据不需要通过第三方转交,可以直接在链路层实现直接交付。 如果主机要发达的ip包,目标ip与主机不属于同一局域网,意味着无法直接交付,需要通过第三方的路由器进行转发,对主机来说,这个缺省的路由器ip地址就是主机配置参数“缺省网关”指定的值。缺省网关与主机同属于一个局域网,它的任务就是向其他网络转发此网内主机收发的ip包。 编程要求 注意,为便于代码阅读,以及书写简洁。 unsigned char 类型重命名为byte; unsigned short 类型重命名为uint16; unsigned int 类型重命名为uint32. 上述类型通过typedef 定义在datalink_arp.h文件当中。 同时为了便于平台的字节顺序与网络字节顺序的转换,在datalink_arp.h文件中,通过宏定义了对应的函数ntohs,htons,ntohl,htonl前两个针对16位无符号整数,后两个针对32位无符号整数。 研读代码可以看出,ntohs与htons的操作是一样,不同命名也是为了方便理解代码。 上述内容代码在任务目录中可查看和复制。 typedef unsigned char byte; typedef unsigned short uint16; typedef unsigned int uint32; typedef int bool; #define true 1 #define false 0 /* 网络字节顺序与本地顺序的转换,对于本地是大端模式的则不需要转换 */ #define htons(x) ((0xff & ((x)>>8)) | ((0xff & (x)) << 8)) #define htonl(x) ((((x)>>24) & 0x000000ff) | (((x)>> 8) & 0x0000ff00) | \ (((x)<<8) & 0x00ff0000) | (((x)<<24) & 0xff000000)) #define ntohs(x) ((0xff & ((x)>>8)) | ( (0xff & (x)) << 8)) #define ntohl(x) ((((x)>>24) & 0x000000ff) | (((x)>> 8) & 0x0000ff00) | \ (((x)<<8) & 0x00ff0000) | (((x)<<24) & 0xff000000)) 实训任务中给出的代码复制到windows平台编译和测试时注意使用版本,如果用的是C++,则bool,false,true均为保留字,则需要删除头文件中的定义。 ####测试说明 从文件中按行读取字符串,获得本地网上配置参数,ip,mask,gate。形如: mask : 255. 255. 255. 0 ip: 192 .168. 9. 1 gate: 192. 168. 9. 254 首列以字母开始,以区分不同参数。 该过程由tools.c中的函数实现: void getconfig(char*file, char *ipstr,char *maskstr,char *gatestr) ;
03-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值