《网络安全编程基础》之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"头文件
解决办法:
在百度知道上看到了这段对话后感觉已经凉了,还好我有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防火墙……
点击"允许访问"后,额……
??☺???
解决办法:
百度一下,发现又打开了一个新世界的大门:
那么这里是由于先运行client.c再运行server.c导致
char recvBuf[50];
recv(socksend,recvBuf,50,0); //recv()
```中数组`recvBuf`未被初始化的原因,解决方法当然是**先运行server.c再运行client.c**咯,这样客户端就能receive到服务器发来的recvBuf啦~
##运行结果
- 一个客户端连接一个服务器:
![tobLT.png](https://s1.ax1x.com/2017/10/20/tobLT.png)
- 多个客户端同时连接一个服务器:
![toOwF.png](https://s1.ax1x.com/2017/10/20/toOwF.png)
##高级版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)
![UKuNV.png](https://s1.ax1x.com/2017/10/25/UKuNV.png)
##参考资料
- [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)