【网络编程02】简单聊天程序
有了上次socket的基础知识,网络编程01 可以写一个简单的聊天程序,随便复习一下基础知识。
1.线程
我们要实现可以同时发送和接收信息,就需要多线程了,一个用于发,一个用于收。
这次用CreateThread来创建线程。函数原型
HANDLE WINAPI CreateThread
( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
函数看着复杂其实用起来很简单。只需要关心传入什么函数,函数参数是什么。
1.第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置
2.第二个参数表示线程栈空间大小。传入0表示使用默认大小
3.第三个参数表示新线程所执行的线程函数地址(函数的名字),多个线程可以使用同一个函数地址
4.第四个参数是传给线程函数的参数。
5.第五个参数指定什么时候调用线程,为0表示线程创建之后立即就可以进行调用。
6.第六个参数返回线程的ID号,传入NULL表示不需要返回该线程ID号
2.服务器端代码
我们把发送信息和接收信息的功能封装成两个函数作为线程使用。
1 #include<stdio.h> 2 #include<string.h> 3 #include<WinSock2.h> 4 #pragma comment (lib,"ws2_32.lib") 5 SOCKET newSocket;//全局变量,用来通信的套接字 6 7 void recvFun();//接收信息线程 8 void sendFun();//发送信息线程 9 void createConnect();//创建通信套接字 10 11 int main() 12 { 13 HANDLE h1, h2;//线程句柄 14 createConnect(); 15 printf("连接成功...\n"); 16 //创建线程后立即运行 17 h1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)sendFun, NULL, 0, NULL); 18 h2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)recvFun, NULL, 0, NULL); 19 WaitForSingleObject(h1, INFINITE);//会阻塞,直到线程结束 20 WaitForSingleObject(h2, INFINITE);//会阻塞,直到线程结束 21 closesocket(newSocket);//关闭套接字 22 return 0; 23 } 24 void sendFun() 25 { 26 char buf[128]; 27 while (1) 28 { 29 printf("你要发送的信息:"); 30 scanf("%s", buf); 31 send(newSocket, buf, strlen(buf) + 1, 0);//发送信息 32 } 33 } 34 35 void recvFun() 36 { 37 char buf[128]; 38 while (1) 39 { 40 recv(newSocket, buf, 128, 0);//接收信息 41 printf("%32s%s\n","接收到的信息: ", buf); 42 } 43 44 } 45 46 void createConnect() 47 { 48 SOCKET serverSocket;//监视的套接字 49 //SOCKET newSocket;//用来通信的套接字 50 SOCKADDR_IN newAddr;//保存客户端的socket地址信息 51 SOCKADDR_IN addr;//地址结构体,包括ip port(端口) 52 WSADATA data; 53 WORD version;//socket版本 54 int info; 55 /* 56 在使用socket之前要进行版本的设定和初始化 57 看不懂不用管 58 */ 59 version = MAKEWORD(2, 2);//设定版本 60 info = WSAStartup(version, &data); 61 /*应用程序或DLL只能在一次成功的WSAStartup()调用之后 62 才能调用进一步的Windows Sockets API函数。 63 根据版本初始化 windows socket,返回0表示成功 64 */ 65 if (info != 0) 66 { 67 printf("初始化失败\n"); 68 return; 69 } 70 if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2) 71 { 72 printf("加载失败\n"); 73 WSACleanup(); 74 return; 75 } 76 //创建套接字,使用TCP协议 77 serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 78 addr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);//表示任何的ip过来连接都接受 79 addr.sin_family = AF_INET;//使用ipv4的地址 80 addr.sin_port = htons(6666);//设定应用占用的端口 81 bind(serverSocket, (SOCKADDR*)&addr, sizeof(SOCKADDR));//将套接字与端口6666,接收的ip绑定 82 listen(serverSocket, 3);//开始监听,是否有客服端请求连接,最大连接数为3 83 printf("开始监听,等待连接..........\n"); 84 int len = sizeof(SOCKADDR); 85 newSocket = accept(serverSocket, (SOCKADDR*)&newAddr, &len); 86 }
3.客户端代码
客户端和服务器端代码差不多,也是两个线程用于接收和发送信息。
1 #include<stdio.h> 2 #include<string.h> 3 #include<WinSock2.h> 4 #pragma comment(lib,"ws2_32.lib") 5 SOCKET clientSocket;//全局变量,用于通信的socket 6 void createConnect();//创建套接字 7 void sendFun();//发送信息线程 8 void recvFun();//接收信息线程 9 int main() 10 { 11 HANDLE h1, h2;//线程句柄,其实就是一串数字用来标识线程对象 12 createConnect();//创建套接字 13 //创建线程后立即执行 14 h1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)sendFun, NULL, 0, NULL); 15 h2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)recvFun, NULL, 0, NULL); 16 WaitForSingleObject(h1, INFINITE);//会阻塞,直到线程运行结束 17 WaitForSingleObject(h2, INFINITE); 18 closesocket(clientSocket);//关闭套接字 19 return 0; 20 } 21 void createConnect() 22 { 23 SOCKADDR_IN addr; 24 int info; 25 WSADATA data; 26 WORD version; 27 //设定版本,与初始化 28 version = MAKEWORD(2, 2); 29 info = WSAStartup(version, &data); 30 if (info != 0) 31 { 32 printf("初始化失败\n"); 33 return; 34 } 35 if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2) 36 { 37 printf("加载失败\n"); 38 WSACleanup(); 39 return; 40 } 41 clientSocket = socket(AF_INET, SOCK_STREAM, 0);//创建套接字 42 //要连接的服务器的ip,因为现在服务器端就是本机,所以写本机ip 43 //127.0.0.1一个特殊的IP地址,表示是本机的IP地址 44 addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 45 //端口要与服务器相同,不然找不到 46 addr.sin_port = htons(6666); 47 //用IPV4地址 48 addr.sin_family = AF_INET; 49 //主动连接服务器 50 connect(clientSocket, (SOCKADDR*)&addr, sizeof(SOCKADDR)); 51 } 52 53 void sendFun() 54 { 55 char buf[128]="你是谁"; 56 while (1) 57 { 58 printf("你要发送的信息: "); 59 scanf("%s", buf); 60 //发送数据 61 send(clientSocket, buf, strlen(buf) + 1, 0); 62 } 63 } 64 65 66 void recvFun() 67 { 68 char buf[128]; 69 //接收服务发送的数据 70 while (1) 71 { 72 recv(clientSocket, buf, 128, 0);//接收数据 73 printf("%32s%s\n","接收的信息为: ", buf); 74 } 75 }
运行结果,可以实现聊天的功能,虽然界面不行。
学了socket编程还可以实现木马之类的东西。原理很简单,让目标用户在后台悄悄运行你的程序,在另一端你可以发送各种命令操作程序从而实现操作用户的电脑,窃取信息。比如你发送个强制关机的命令的 str="shutdown -s -f",而目标用户的程序接收到了这个命令并且调用了 system(str)。目标用户的电脑马上就会关机。