《網絡安全編程基礎》之Socket編程
我的代碼
server.c
// server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Winsock2.h>
#pragma comment(lib,"ws2_32.lib") //添加靜態鏈接庫文件
void main(int argc,char* argv[])
{
WSADATA wsadata;
WSAStartup(MAKEWORD(1,1),&wsadata);
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); //socket()
/***地址結構體***/
SOCKADDR_IN addrSvr;
addrSvr.sin_family=AF_INET;
addrSvr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSvr.sin_port=htons(6000);
/**************/
bind(sockSrv,(SOCKADDR*)&addrSvr, sizeof(SOCKADDR)); //bind()
listen(sockSrv,5); //listen()
SOCKADDR_IN addrClient;
int len= sizeof(SOCKADDR);
while(1) //加循環是為了應對多個客戶端連接此服務器的情況
{
SOCKET socksend=accept(sockSrv,(SOCKADDR*)&addrClient,&len); //accept()
char sendBuf[50]; //
sprintf(sendBuf,"你好,我是服務器"); //使用sprintf給字符串賦值、連接字符串比較方便
send(socksend,sendBuf,strlen(sendBuf)+1,0); //send(),+1是因為字符串以'\0'結尾
char recvBuf[50];
recv(socksend,recvBuf,50,0); //recv()
printf("%s\n",recvBuf);
closesocket(socksend);
}
/*closesocket(sockSrv);
WSACleanup();*/ //while(1)后的死代碼
}
client.c
// Client.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Winsock2.h>
#pragma comment(lib,"ws2_32.lib") //添加靜態鏈接庫文件
void main(int argc,char* argv[])
{
WSADATA wsadata;
WSAStartup(MAKEWORD(1,1),&wsadata);
SOCKET socketClient=socket(AF_INET,SOCK_STREAM,0); //socket()
/***地址結構體***/
SOCKADDR_IN addrSvr;
addrSvr.sin_family=AF_INET;
addrSvr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSvr.sin_port=htons(6000);
/**************/
connect(socketClient,(SOCKADDR*)&addrSvr,sizeof(SOCKADDR)); //connect()
char recvBuf[50];
recv(socketClient,recvBuf,50,0); //recv()
printf("%s\n",recvBuf);
send(socketClient,"你好,我是客戶端",strlen("你好,我是客戶端")+1,0); //send()
closesocket(socketClient);
WSACleanup();
}
代碼調試過程中出現的問題
問題一:macOS High Sierra下Clion出現CMake Error
解決辦法:百度無果,重新打開Clion發現連license都過期了,多半是沒救了,只能老老實實用命令行試試了>_<
問題二:終端下編譯server.c提示找不到"winsock2.h"頭文件
解決辦法:
Mac下編程用什么替換windows.h頭文件?
我在mac下編程,想使用清屏指令cls不好使,也不能用windows.h頭文件。請大家幫我想想怎么辦。還有在mac下能用system" "么?
不行,你不能在除了 Windows 的任何系統上使用 Windows.h。你要理解 API 的概念,windows.h 這個頭文件是 Windows 帶的,而不是 C 語言自身有的。事實上,出了 Windows,沒有任何系統——實際上也是在真真切切用 C 的系統——例如所有在跑類 Unix,比如 OS X、Linux 甚至 FreeBSD 上的,都不能用 Windows 這套 API。這也是為什么坊間都說 OS X 是適合做編程,特別是適合學編程的,因為 OS X 是“體制內”,也就使用和全世界除了 Windows 之外所有的東西都互通的底層架構的,而且它在過去的大部分時候都要比各類 Linux 要容易上手,所謂的“更優雅”。
……
在百度知道上看到了這段對話后感覺已經涼了,還好我有windows8.1虛擬機,這回再也不怕找不到windows頭文件了吧!
問題三:windows8.1虛擬機不兼容VC6.0
解決辦法:
- 右擊Visual C++ 6.0快捷方式,選擇"屬性",在"目標(T):"中查看其可執行文件的地址為:"C:\Program Files (x86)\Microsoft Visual Studio\Common\MSDev98\Bin\MSDEV.EXE",找到MSDEV.EXE;
- 右鍵選擇"屬性",在"常規"選項卡下將MSDEV.EXE更名為MSDEV1.EXE:
- 在"兼容性"選項卡下勾選"以兼容模式運行這個程序",將兼容模式選擇Windows XP(Service Pack2)",並將權限等級勾選為“以管理員身份運行此程序”,點擊確定:
- 重新運行Visual C++ 6.0,奈斯,已經成功了!
- 老規矩,新建一個Win32控制台工程,並以Hello World方式打開:
- 盡情開始你的表演吧~
問題四:編譯error1——在編譯VC時候,出現fatal error C1010: unexpected end of file while looking for precompiled head
問題詳細解釋:
致命錯誤C1010,在尋找預編譯指示頭文件時,文件未預期結束。就是沒有找到預編譯指示信息的問文件。顧名思義就是預編譯因為缺少了預編譯文件而失敗。解決方法顯然可以取消預編譯,或者幫助編譯器找到預編譯文件。
解決辦法:
- 右鍵單擊項目工程中的cpp文件,在菜單Project-->Settings-->C/C++-->Precompile Header,設置為第一項:Not using precompile headers。
- 在.cpp文件開頭添加包含文件stdafx.h:
#include "stdafx.h"
- 重新編譯即可~
問題五:編譯error2——地址結構體大小寫表示問題
解決辦法:
不知道是不是編譯環境不同的原因,學校電腦上的地址結構體成員addrSvr.sin_Family
到我win8.1虛擬機上就必須改成addrSvr.sin_family
了,滿臉黑線= =
問題六:編譯error3——sendBuf未定義
解決辦法:
自己疏忽原因,在前面加上char sendBuf[50]
即可~
至此,編譯終於成功通過orz...
問題七:燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙燙
點擊運行,彈出Windows防火牆……
點擊"允許訪問"后,額……
??☺???
解決辦法:
百度一下,發現又打開了一個新世界的大門:
問題根源:
在windows平台下,ms的編譯器(也就是vc帶的那個)在 Debug 模式下,會把未初始化的棧內存全部填成 0xcc,用字符串來看就是”燙燙燙燙燙燙燙”,未初始化的堆內存全部填成0xcd,字符串看就是“屯屯屯屯屯屯屯屯”。
說人話:定義的字符串沒有初始化就會出現這樣的情況
解決辦法:初始化一下
- char p[] = “0”;
- ZeroMemory
- memset
那么這里是由於先運行client.c再運行server.c導致
char recvBuf[50];
recv(socksend,recvBuf,50,0); //recv()
```中數組`recvBuf`未被初始化的原因,解決方法當然是**先運行server.c再運行client.c**咯,這樣客戶端就能receive到服務器發來的recvBuf啦~
##運行結果
- 一個客戶端連接一個服務器:

- 多個客戶端同時連接一個服務器:

##高級版mySocket——實現服務器客戶端互發消息尬聊>_<
###核心偽代碼
- server.c:
```
do{
gets(sendBuf);
send();
recv();
puts(recvBuf);
}while(返回值不為-1);
```
- client.c:
```
do{
recv();
puts(recvBuf);
gets(sendBuf);
send();
}while(返回值不為-1);
```
###完整代碼
- server.c:
```
// server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //添加靜態鏈接庫文件
void main(int argc,char* argv[])
{
WSADATA wsadata;
WSAStartup(MAKEWORD(1,1),&wsadata);
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); //socket()
/***地址結構體***/
SOCKADDR_IN addrSvr;
addrSvr.sin_family=AF_INET;
addrSvr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSvr.sin_port=htons(6000);
/**************/
bind(sockSrv,(SOCKADDR*)&addrSvr, sizeof(SOCKADDR)); //bind()
listen(sockSrv,5); //listen()
SOCKADDR_IN addrClient;
int len= sizeof(SOCKADDR);
while(1)
{
SOCKET socksend=accept(sockSrv,(SOCKADDR*)&addrClient,&len); //accept()
char sendBuf[50];
char recvBuf[50];
int a;
do{
printf("Me:");
gets(sendBuf);
fflush(stdin);
send(socksend,sendBuf,strlen(sendBuf)+1,0); //send(),+1是因為字符串以'\0'結尾
a=recv(socksend,recvBuf,50,0); //recv()
printf(" Client:%s\n",recvBuf);
}while(a!=-1);
closesocket(socksend);
}
closesocket(sockSrv);
WSACleanup();
}
```
- client.c:
```
// Client.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Winsock2.h>
#pragma comment(lib,"ws2_32.lib") //添加靜態鏈接庫文件
void main(int argc,char* argv[])
{
WSADATA wsadata;
WSAStartup(MAKEWORD(1,1),&wsadata);
SOCKET socketClient=socket(AF_INET,SOCK_STREAM,0); // socket()
/***地址結構體***/
SOCKADDR_IN addrSvr;
addrSvr.sin_family=AF_INET;
addrSvr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSvr.sin_port=htons(6000);
/**************/
connect(socketClient,(SOCKADDR*)&addrSvr,sizeof(SOCKADDR));
char recvBuf[50];
char sendBuf[50];
int a;
do{
a=recv(socketClient,recvBuf,50,0);
printf(" Server:%s\n",recvBuf);
printf("Me:");
gets(sendBuf);
fflush(stdin);
send(socketClient,sendBuf,strlen(sendBuf)+1,0);
}while(a!=1);
closesocket(socketClient);
WSACleanup();
}
```
###運行結果(這不是尬聊是什么hhh)

##參考資料
- [Mac&iOS Socket編程](http://m.blog.csdn.net/bravegogo/article/details/50938454)
- [Mac下編程用什么替換windows.h頭文件](https://zhidao.baidu.com/question/369558222732704524.html?fr=ala&word=mac下windows頭文件)
- [如何在win8.1下運行VC6.0](https://jingyan.baidu.com/article/2009576198453dcb0721b4a1.html)
- [關於SOCKET編程中“燙燙燙...”的問題](http://m.blog.csdn.net/zhichitianya1234/article/details/76291374)
- [文件寫入或控制台輸出顯示:"燙燙燙燙"問題解決辦法](http://m.blog.csdn.net/alex__0805/article/details/47381531)