上机考试作弊,也不是不可以呢
前言
这学期的C++课学校用了北理工的一套软件,大概一两周就有一次上机考试,软件的防作弊机制就是每个学号绑定一个IP地址,单学号登录多IP、单IP被多个学号登录都会触发重修小彩蛋。不过,正所谓时势造英雄,当人人都在抱怨的时候为什么不想一个脱离防作弊机制的手段呢?
本文将介绍我前段时间写的一个程序,基于TCP的Winsock编程实现文件的传送。考试时大家埋头思索,这时候把答案通过IP地址传送给喜欢的妹子,脱单似乎就近在咫尺了啊。
思路
Winsock的学习看微软官网手册就够了,一步一步跟着敲下来,基本上就算是入门了。
下面简单讲一下Winsock编程的基本思路:
Server端:创建嵌套字并初始化,创建socket,初始化socket(将端口号及IP地址绑定),listen监听,accept不断接受连接,接受到连接后,捕获socket,recv获得内容,通信完成后关闭socket。
Client端:创建嵌套字并初始化,创建socket,绑定端口号及目标IP地址,connect连接服务器,send发送消息,通信结束后关闭socket。
完整代码
使用软件:codeblocks
用户端:TransferFile-Client.cpp
1 // TransferFile-Client.cpp:Define the entry point for the console application. 2 // Program Function : Transfer file by C/S : Part Client 3 // Author : zhaoyixiang 4 // E-mail : 674965440@qq.com 5 // Date : 2018-5-1 6 7 #define _WIN32_WINNT 0x501 8 #include <winsock2.h> 9 #include <ws2tcpip.h> 10 #include <iphlpapi.h> 11 #include <stdio.h> 12 #include <cstring> 13 14 #pragma comment(lib, "Ws2_32.lib") 15 16 #define DEFAULT_PORT "27015" 17 #define DEFAULT_BUFLEN 512 18 19 using namespace std; 20 21 int main(int argc, char const *argv[]) 22 { 23 WSADATA wsaData; 24 25 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 26 if (iResult != 0) 27 { 28 printf("WSAStartup failed: %d\n", iResult); 29 return 1; 30 } 31 32 33 /* 34 Creating a Socket for the Client 35 Declare an addrinfo object that contains a sockaddr structure and initialize these values. 36 For this application, the Internet address family is unspecified 37 so that either an IPv6 or IPv4 address can be returned. 38 The application requests the socket type to be a stream socket for the TCP protocol. 39 */ 40 struct addrinfo *result = NULL, *ptr = NULL, hints; 41 ZeroMemory(&hints, sizeof(hints)); 42 hints.ai_family = AF_UNSPEC; 43 hints.ai_socktype = SOCK_STREAM; 44 hints.ai_protocol = IPPROTO_TCP; 45 46 // Resolve the server address and port 47 iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result); 48 if (iResult != 0) 49 { 50 printf("getaddrinfo failed: %d\n", iResult); 51 WSACleanup(); 52 return 1; 53 } 54 55 56 57 char temp[DEFAULT_BUFLEN]; 58 strcpy(temp, "main.cpp"); 59 // create file 60 FILE * fp = fopen(temp, "rb"); // binary mode for read 61 if(fp == NULL) 62 { 63 printf("open file %s failed\n", temp); 64 return -1; 65 } 66 67 SOCKET ConnectSocket = INVALID_SOCKET; 68 ptr = result; 69 ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); 70 if (ConnectSocket == INVALID_SOCKET) 71 { 72 printf("Error at socket(): %ld\n", WSAGetLastError()); 73 freeaddrinfo(result); 74 WSACleanup(); 75 return 1; 76 } 77 78 79 /* 80 Connecting to a Socket 81 For a client to communicate on a network, it must connect to a server. 82 */ 83 iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 84 if (iResult == SOCKET_ERROR) 85 { 86 printf("Unable to connect to server!\n"); 87 WSACleanup(); 88 return 1; 89 } 90 91 92 /* 93 Sending and Receiving Data on the Client 94 */ 95 int recvbuflen = DEFAULT_BUFLEN; 96 char recvbuf[DEFAULT_BUFLEN]; 97 char sendbuf[DEFAULT_BUFLEN]; 98 99 int num = 0; 100 while(!feof(fp)) 101 { 102 num = fread(temp, 1, DEFAULT_BUFLEN, fp); 103 send(ConnectSocket, temp, num, 0); 104 } 105 printf("server file transfer success\n"); 106 107 fclose(fp); 108 109 110 iResult = shutdown(ConnectSocket, SD_SEND); 111 if (iResult == SOCKET_ERROR) 112 { 113 printf("Shutdown failed: %d\n", WSAGetLastError()); 114 closesocket(ConnectSocket); 115 WSACleanup(); 116 return 1; 117 } 118 119 closesocket(ConnectSocket); 120 121 122 WSACleanup(); 123 return 0; 124 }
服务端:TransferFile-Server.cpp
1 // TranferFile-Server.cpp:Define the entry point for the console application. 2 // Program Function : Transfer file by C/S : Part Server 3 // Author : zhaoyixiang 4 // E-mail : 674965440@qq.com 5 // Date : 2018-5-1 6 7 #define _WIN32_WINNT 0x501 8 #include <winsock2.h> 9 #include <ws2tcpip.h> 10 #include <iphlpapi.h> 11 #include <stdio.h> 12 #include <cstring> 13 14 #pragma comment(lib, "Ws2_32.lib") 15 16 #define DEFAULT_PORT "27015" 17 #define DEFAULT_BUFLEN 512 18 19 using namespace std; 20 21 int main(int argc, char const *argv[]) 22 { 23 WSADATA wsaData; 24 25 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 26 if (iResult != 0) 27 { 28 printf("WSAStartup failed: %d\n", iResult); 29 return 1; 30 } 31 32 33 char file_name[DEFAULT_BUFLEN]; 34 char temp[DEFAULT_BUFLEN]; 35 strcpy(file_name, "receive test"); 36 //create file 37 FILE *fp = fopen(file_name, "wb"); 38 if(fp == NULL) 39 { 40 printf("create file %s failed\n", file_name); 41 return -1; 42 } 43 44 45 /* 46 Creating a Socket for the Server 47 */ 48 struct addrinfo *result = NULL, hints; 49 50 ZeroMemory(&hints, sizeof(hints)); 51 hints.ai_family = AF_INET; 52 hints.ai_socktype = SOCK_STREAM; 53 hints.ai_protocol = IPPROTO_TCP; 54 hints.ai_flags = AI_PASSIVE; 55 56 iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 57 if (iResult != 0) 58 { 59 printf("getaddrinfo failed: %d\n", iResult); 60 WSACleanup(); 61 return 1; 62 } 63 SOCKET ListenSocket = INVALID_SOCKET; 64 ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 65 if (ListenSocket == INVALID_SOCKET) 66 { 67 printf("Error at sock(): %ld\n", WSAGetLastError()); 68 freeaddrinfo(result); 69 WSACleanup(); 70 return 1; 71 } 72 73 74 /* 75 Binding a Socket 76 For a server to accept client connections, 77 it must be bound to a network address within the system. 78 */ 79 iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 80 if (iResult == SOCKET_ERROR) 81 { 82 printf("bind failed: %d\n", WSAGetLastError()); 83 freeaddrinfo(result); 84 closesocket(ListenSocket); 85 WSACleanup(); 86 return 1; 87 } 88 freeaddrinfo(result); 89 90 91 92 /* 93 Listening on a Socket 94 After the socket is bound to an IP address and port on the system, 95 the server must then listen on that IP address and port 96 for incoming connection requests. 97 */ 98 if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) 99 { 100 printf("Listen failed with error: %d\n", WSAGetLastError()); 101 closesocket(ListenSocket); 102 WSACleanup(); 103 return 1; 104 } 105 106 107 /* 108 Accepting a Connection 109 Once the socket is listening for a connection, 110 the program must handle connection requests on that socket. 111 */ 112 SOCKET ClientSocket; 113 ClientSocket = INVALID_SOCKET; 114 ClientSocket = accept(ListenSocket, NULL, NULL); 115 if (ClientSocket == INVALID_SOCKET) 116 { 117 printf("accept failed: %d\n", WSAGetLastError()); 118 closesocket(ListenSocket); 119 WSACleanup(); 120 return 1; 121 } 122 123 124 /* 125 Receiving and Sending Data on the Server 126 */ 127 char recvbuf[DEFAULT_BUFLEN]; 128 int iSendResult; 129 int recvbuflen = DEFAULT_BUFLEN; 130 131 132 //receive data from server 133 int num = 0; 134 while (1) 135 { 136 num = recv(ClientSocket, temp, DEFAULT_BUFLEN, 0); 137 if(0 == num) 138 break; 139 fwrite(temp, 1, num, fp); 140 } 141 printf("transmission done\n"); 142 143 fclose(fp); 144 145 146 // shutdown the connection for sending since no more data will be sent 147 // the client can still use the ConnectSocket for receiving data 148 iResult = shutdown(ClientSocket, SD_SEND); 149 if (iResult == SOCKET_ERROR) 150 { 151 printf("shutdown failed: %d\n", WSAGetLastError()); 152 closesocket(ClientSocket); 153 WSACleanup(); 154 return 1; 155 } 156 157 // cleanup 158 closesocket(ClientSocket); 159 160 161 162 WSACleanup(); 163 164 return 0; 165 }
注意事项
codeblocks调用API还是比较麻烦的
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
以上是常规操作,而cb想编译成功的话则需进行一下操作:
选择project -> Build options
Linker settings -> other linker options -> 输入-lws2_32 -> OK
该文章在csdn发过,所以图片有水印,原创。
使用方法
先运行server文件,再用命令行运行client文件并输入接受方的IP地址,事先准备好的main.cpp(可以更换名称)即可发送。
Teamwork时,自己持有Client文件,给妹子Server文件,然后趁着月黑风高为所欲为。
补充
当然了,真正操作的时候不要傻乎乎的将生成的TransferFile-Client.exe / TransferFile-Server.exe文件直接摆在桌面上,监考老师只要学过英语就能发现你在作弊好吧!!!
到网上搜一个教程把文件图标改了,再把文件名改成常用软件名,例如notepad++,这样老师一般不会注意到。
总结
据说点赞的人一周之内都会脱单。。。(逃