人生难得是欢聚,唯有别离多

【网络编程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)。目标用户的电脑马上就会关机。

posted @ 2020-04-24 14:37  对愁眠  阅读(594)  评论(0编辑  收藏  举报