【前言】 Windows 下的 socket 程序依赖 Winsock.dll 或 ws2_32.dll,必须提前加载。动态链接库有两种加载方式:隐式加载和显示加载。请查看:动态链接库DLL的加载 (此处是引用别人的文章)。本文是在vs下添加ws2_32.dll库。
右键【项目】-【属性】-【链接器】-【输入】-【附加依赖项】,进行编辑,添加 ws2_32.dll库,去掉从父级或项目默认设置继承的勾选,如下图所示:
注意,下面的服务器端和客户端代码均写入了这一句——#pragma comment(lib, "ws2_32.lib") //加载 ws2_32.dll,因此两个程序都需要添加ws2_32.lib动态链接库。
#include
#include
#pragma comment (lib, "ws2_32.lib") //加载 ws2_32.dll
int main(){
//初始化 DLL
WSADATA wsaData;
WSAStartup( MAKEWORD(2, 2), &wsaData);
//创建套接字
SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//绑定套接字
sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充
sockAddr.sin_family = PF_INET; //使用IPv4地址
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
sockAddr.sin_port = htons(1234); //端口
bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
//进入监听状态
listen(servSock, 20);
//接收客户端请求
SOCKADDR clntAddr;
int nSize = sizeof(SOCKADDR);
SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);
//向客户端发送数据
char *str = "Hello World!";
send(clntSock, str, strlen(str)+sizeof(char), NULL);
//关闭套接字
closesocket(clntSock);
closesocket(servSock);
//终止 DLL 的使用
WSACleanup();
return 0;
}
在运行服务器端代码时,有的vs会出现如下错误error C4996: 'inet_addr': Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings,如下图:
这是因为inet_addr是一个老函数,而微软就是喜欢强迫别人用它的新函数。
【解决方案】
1. 用socket的新函数代替程序出现的所有老函数,此方法学习成本太高。
2. 在项目属性里设置,告诉编译器,我就用老函数,让她不要报错了。
所以推荐使用第二种解决方案,设置方法如下:
右键【项目】-【属性】-【配置属性】-【C/C++】-【常规】-【SDL检查】的值改为“否”,如下图:
再次运行,就不会报错了。
#include
#include
#include
#pragma comment(lib, "ws2_32.lib") //加载 ws2_32.dll
int main(){
//初始化DLL
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//向服务器发起请求
sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockAddr.sin_port = htons(1234);
connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
//接收服务器传回的数据
char szBuffer[MAXBYTE] = {0};
recv(sock, szBuffer, MAXBYTE, NULL);
//输出接收到的数据
printf("Message form server: %s\n", szBuffer);
//关闭套接字
closesocket(sock);
//终止使用 DLL
WSACleanup();
system("pause");
return 0;
}
先运行 服务器端程序,再运行客户端程序,输出结果为:
Message form server: Hello World!
值得注意的是,由于这两个程序没有写入while循环,所以server 只接受一次 client 请求,当 server 向 client 传回数据后,程序就运行结束了。如果想再次接收到服务器的数据,必须再次运行 server,这只是一个非常简陋的 socket 程序,不能够一直接受客户端的请求。
本文的存在,只是为了讲述在vs环境下,跑通Socket程序的流程以及会遇到的问题及解决方法。