【網絡編程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)。目標用戶的電腦馬上就會關機。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章