MAKEWORD(2,2)解释

宏的原始定义:#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
返回值:一个无符号16位整形数。

例子:

WORD wVersionRequested;
wVersionRequested = MAKEWORD( 2, 2 );
#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8))

makeword是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)
makelparam、makelong和makewparam都是一样的,将两个word型合并成一个dword型。一个在高16位,一个在低16位
delphi:word((byte(a)) or (word(byte(b))) shl 8);
比如a=2;b=1
2的二进制是00000010 1的二进制为00000001 B是表示高8位,A表示低8位 合并起来就是
100000010
MAKEWORD(1,1)和MAKEWORD(2,2)的区别在于,前者只能一次接收一次,不能马上发送,而后者能。
比如:

#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
WORD wVersionRequested;
wVersionRequested=MAKEWORD(2,2);
cout << wVersionRequested << endl;
return 0;
}

输出的结果是514,
而这个结果正是:512 + 2 = 514.

socket编程中:
声明调用不同的Winsock版本。例如MAKEWORD(2,2)就是调用2.2版,MAKEWORD(1,1)就是调用1.1版。
不同版本是有区别的,例如1.1版只支持TCP/IP协议,而2.0版可以支持多协议。2.0版有良好的向后兼容性,任何使用1.1版的源代码、二进制文件、应用程序都可以不加修改地在2.0规范下使用。此外winsock 2.0支持异步 1.1不支持异步.

### 服务端代码详解及注释 ```c #define DEFAULT_PORT 5050 // 服务端的默认端口号为 5050 #define BUFFER_SIZE 1024 // 缓冲区大小 #define _WINSOCK_DEPRECATED_NO_WARNINGS // 忽略 Winsock 过时警告 #include <stdio.h> #include <string.h> #include <winsock2.h> #include <ws2tcpip.h> #include <process.h> // 添加这个头文件以使用 _beginthreadex #pragma comment(lib, "ws2_32.lib") // 告诉编译器链接 Winsock 库 // 处理客户端连接的线程函数 unsigned __stdcall thread_func(void* lpThreadParameter) { SOCKET s_client = *(SOCKET*)lpThreadParameter; // 从参数中获取客户端套接字 free(lpThreadParameter); // 释放分配的内存 while (1){ // 5. 开始通讯 char mode[BUFFER_SIZE] = {0}; int ret = recv(s_client, mode, BUFFER_SIZE, 0); // 接收模式('d' 或 'f') if (ret <= 0) break; // 如果接收失败或客户端断开连接,退出循环 if (strcmp(mode, "d") == 0) { // 接收普通文本数据 char buffer[BUFFER_SIZE] = {0}; ret = recv(s_client, buffer, BUFFER_SIZE, 0); // 接收实际数据 if (ret <= 0) break; // 如果接收失败或客户端断开连接,退出循环 printf("--客户端%llu 的数据传输结果如下所示:\n", s_client); printf("TCP Server Receive: %s\n", buffer); // 打印接收到的数据 send(s_client, buffer, (int)strlen(buffer), 0); // 将接收到的数据回传给客户端 printf("TCP Server Send: %s\n", buffer); // 打印发送的数据 } else if (strcmp(mode, "f") == 0) { // 接收文件 char filename[BUFFER_SIZE] = {0}; int ret = recv(s_client, filename, BUFFER_SIZE, 0); // 接收文件名 if (ret <= 0) break; // 如果接收失败或客户端断开连接,退出循环 FILE *fp = fopen(filename, "wb"); // 以二进制写入模式打开文件 if (!fp) { printf("Failed to create file.\n"); continue; } while (1) { char buffer[BUFFER_SIZE] = {0}; ret = recv(s_client, buffer, BUFFER_SIZE, 0); // 接收文件内容 if (ret <= 0) break; // 如果接收失败或客户端断开连接,退出循环 fwrite(buffer, 1, ret, fp); // 写入文件 if (ret < BUFFER_SIZE) break; // 文件传输结束 } fclose(fp); // 关闭文件 printf("--来自客户端%llu的文件%s成功接收并保存\n", s_client, filename); // 打印接收成功的消息 } // else { // printf("Unknown mode: %s\n", mode); // } } printf("**客户端: %llu 断开连接.\n", s_client); // 打印客户端断开连接的信息 closesocket(s_client); // 关闭客户端套接字 _endthreadex(0); // 结束线程 return 0; } int main(int argc, char *argv[]) { int iPort = DEFAULT_PORT; // 初始化 Winsock 库,版本为 2.2 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Failed to load Winsock.\n"); return -1; } // 1. 创建一个 IPv4 的流式套接字 SOCKET s_listen = socket(AF_INET, SOCK_STREAM, 0); if (s_listen == INVALID_SOCKET) { printf("socket() Failed: %d\n", WSAGetLastError()); return -1; } printf("--监听套接字为 %d\n", s_listen); // 2. 绑定端口号和 IP 地址 struct sockaddr_in local = {0}; // 定义本地地址结构体 local.sin_family = AF_INET; // 设置地址族为 IPv4 local.sin_port = htons(iPort); // 设置端口号,并将其转换为网络字节序 local.sin_addr.s_addr = htonl(INADDR_ANY); // 设置 IP 地址为任意可用地址和接口 if (bind(s_listen, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) { printf("bind() Failed!!! errcode: %d\n", WSAGetLastError()); return -1; } // 3. 监听属性 if (listen(s_listen, 10) == SOCKET_ERROR) { // 开始监听连接请求,最大排队数量为 10 printf("start listen failed!!! errcode: %d\n", WSAGetLastError()); return -1; } // 4. 等待客户端连接 while (1) { SOCKET s_client = accept(s_listen, NULL, NULL); // 接受客户端连接 if (s_client == INVALID_SOCKET) { // 检查连接是否成功 continue; } printf("**端口号: %llu 成为新连接\n", s_client); SOCKET* sockfd = (SOCKET*)malloc(sizeof(SOCKET)); // 分配内存存储客户端套接字 *sockfd = s_client; // 将客户端套接字赋值给新分配的内存 unsigned threadId; // 定义线程 ID _beginthreadex(NULL, 0, thread_func, sockfd, 0, &threadId); // 创建新线程处理客户端连接 } // 清理资源 WSACleanup(); return 0; } ``` ### 客户端代码详解及注释 ```c #define DEFAULT_PORT 5050 // 默认端口号 #define BUFFER_SIZE 1024 // 缓冲区大小 #define _WINSOCK_DEPRECATED_NO_WARNINGS // 忽略 Winsock 过时警告 #include <stdio.h> #include <string.h> #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") // 告诉编译器链接 Winsock 库 int main() { int iPort = DEFAULT_PORT; WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 初始化 Winsock 库,版本为 2.2 // 1. 创建一个 IPv4 流式套接字 SOCKET s_client = socket(AF_INET, SOCK_STREAM, 0); if (s_client == INVALID_SOCKET) { printf("socket() Failed: %d\n", WSAGetLastError()); return -1; } // 2. 连接服务器 struct sockaddr_in target = {0}; // 定义目标地址结构体 target.sin_family = AF_INET; // 设置地址族为 IPv4 target.sin_port = htons(iPort); // 设置端口号,并将其转换为网络字节序 target.sin_addr.s_addr = inet_addr("127.0.0.1"); // 将主机数转换成无符号长整形的网络字节顺序 if (-1 == connect(s_client, (struct sockaddr*)&target, sizeof(target))) { printf("connect server failed!!!\n"); closesocket(s_client); return -1; } while (1) { char choice[10]; printf("请选择传输普通数据还是文件 (d/f): "); scanf("%s", choice); if (strcmp(choice, "d") == 0) { // 发送普通文本数据 send(s_client, "d", strlen("d"), 0); // 发送模式标志 'd' char sbuffer[BUFFER_SIZE] = {0}; // 定义发送数据的缓冲区 printf("请输入数据: "); scanf("%s", sbuffer); send(s_client, sbuffer, strlen(sbuffer), 0); // 将数据发送到服务器 char rbuffer[BUFFER_SIZE] = {0}; // 定义接收数据的缓冲区 int ret = recv(s_client, rbuffer, BUFFER_SIZE, 0); // 接收服务器返回的数据 if (ret <= 0) break; // 如果接收失败或服务器断开连接,退出循环 printf("--服务器成功接收到数据:%s\n", rbuffer); // 打印接收到的数据 } else if (strcmp(choice, "f") == 0) { // 发送文件 send(s_client, "f", strlen("f"), 0); // 发送模式标志 'f' char filename[BUFFER_SIZE] = {0}; printf("请输入文件名: "); scanf("%s", filename); FILE *fp = fopen(filename, "rb"); // 以二进制读取模式打开文件 if (!fp) { printf("该文件不存在,请重新输入.\n"); continue; } send(s_client, filename, strlen(filename), 0); // 发送文件名 while (1) { char buffer[BUFFER_SIZE] = {0}; size_t bytes_read = fread(buffer, 1, BUFFER_SIZE, fp); // 读取文件内容 if (bytes_read > 0) { send(s_client, buffer, bytes_read, 0); // 发送文件内容 } if (bytes_read < BUFFER_SIZE) break; // 文件传输结束 } fclose(fp); // 关闭文件 printf("--文件已发送.\n"); } else { printf("输入无效,请重新选择\n"); } } // 4. 关闭连接 closesocket(s_client); WSACleanup(); // 清理 Winsock 资源 return 0; } ``` ### 总结 - **服务端**: - 初始化 Winsock 库。 - 创建并绑定一个监听套接字。 - 监听客户端连接请求。 - 接受客户端连接后,创建新线程处理每个客户端。 - 在线程中,根据客户端发送的模式(`d` 表示普通数据,`f` 表示文件)进行相应的处理。 - 处理完客户端请求后,关闭套接字并结束线程。 - **客户端**: - 初始化 Winsock 库。 - 创建并连接到服务端。 - 根据用户选择(`d` 表示普通数据,`f` 表示文件),向服务端发送相应数据。 - 对于普通数据,发送并接收回传的数据。 - 对于文件,先发送文件名,再逐块发送文件内容。 - 最后关闭连接并清理 Winsock 资源。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值