学习记录
学习一下创建动态链接库,封装一个Socket客户端dll
1. vs新建文件
2. pch.h文件,申明函数接口
extern “C”:是C++特有的指令(C无法使用该指令),目的在于支持C++与C混合编程。作用是告诉C++编译器用C规则编译指定的代码(除函数重载外,extern “C”不影响C++其他特性)。
dllexport是在这些类、函数以及数据的申明的时候使用。用他表明这些东西可以被外部函数使用,即(dllexport)是把 DLL中的相关代码(类,函数,数据)暴露出来为其他应用程序使用。使用了(dllexport)关键字,相当于声明了紧接在(dllexport)关键字后面的相关内容是可以为其他程序使用的。
dllimport是在外部程序需要使用DLL内相关内容时使用的关键字。当一个外部程序要使用DLL 内部代码(类,函数,全局变量)时,只需要在程序内部使用(dllimport)关键字声明需要使用的代码就可以了,即(dllimport)关键字是在外部程序需要使用DLL内部相关内容的时候才使用。(dllimport)作用是把DLL中的相关代码插入到应用程序中。
_declspec(dllexport)与_declspec(dllimport)是相互呼应,只有在DLL内部用dllexport作了声明,才能在外部函数中用dllimport导入相关代码。
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#ifndef PCH_H
#define PCH_H
// 添加要在此处预编译的标头
#include "framework.h"
#endif //PCH_H
extern "C"
{
_declspec(dllexport) bool tcp_client_init(const char* ip, int iPort);
_declspec(dllexport) bool tcp_client_send(char* buff, int len);
_declspec(dllexport) int tcp_client_rcv(char* buff, int* len);
_declspec(dllexport) int close_tcp_client();
};
3. pch.cpp文件
// pch.cpp: 与预编译标头对应的源文件
#include "pch.h"
// 当使用预编译的头时,需要使用此源文件,编译才能成功。
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
static SOCKET sClient;
#define CLENT_NUM 1
static SOCKET sSever, sSever_c[CLENT_NUM];
struct sockaddr_in sSever_c_sd[CLENT_NUM];
#define USER_ERROR -1
bool tcp_client_init(const char* ip, int iPort)
{
struct sockaddr_in ser; //服务器端地址
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Failed to load Winsock.\n"); //Winsock 初始化错误
return false;
}
ser.sin_family = AF_INET; //初始化服务器地址信息
ser.sin_port = htons(iPort); //端口转换为网络字节序
ser.sin_addr.s_addr = inet_addr(ip); //IP 地址转换为网络字节序
sClient = socket(AF_INET, SOCK_STREAM, 0); //创建客户端流式套接字
if (sClient == INVALID_SOCKET)
{
printf("socket() Failed: %d\n", WSAGetLastError());
return false;
}
//请求与服务器端建立 TCP 连接
if (connect(sClient, (struct sockaddr*)&ser, sizeof(ser)) == INVALID_SOCKET)
{
printf("connect() Failed: %d\n", WSAGetLastError());
return false;
}
printf("socket connect ok\n");
return true;
}
bool tcp_client_send(char* buff, int len)
{
send(sClient, buff, len, 0);
return true;
}
int tcp_client_rcv(char* buff, int* len)
{
int iLen; //从服务器端接收的数据长度
iLen = recv(sClient, buff, 1024, 0); //从服务器端接收数据
if (iLen == 0)
return -1;
else if (iLen == SOCKET_ERROR)
{
printf("recv() Failed: %d\n", WSAGetLastError());
return -1;
}
else
printf("recv() data from server: %s\n", buff); // 输出接收数据
*len = iLen;
return iLen;
}
int close_tcp_client()
{
closesocket(sClient); //关闭 socket
WSACleanup();
printf("socket close\n");
return 0;
}
完成了这两个文件的修改,直接重新生成即可在程序文件夹内得到dll和lib
4. 使用dll和lib
直接新建一个工程,将lib文件放在工程目录,dll文件放在exe目录下
在 .h文件中添加如下
#ifdef __cplusplus
#pragma comment(lib, "TcpDll.lib")
#pragma comment(lib, "ServerTcpDLL.lib")
extern "C" {
#endif
__declspec(dllimport) bool __stdcall tcp_client_init(const char* ip, int iPort);
__declspec(dllimport) bool __stdcall tcp_client_send(char* buff, int len);
__declspec(dllimport) int __stdcall tcp_client_rcv(char* buff, int* len);
__declspec(dllimport) int __stdcall close_tcp_client();
#ifdef __cplusplus
}
#endif
做完这一步,直接在cpp内使用该函数即可。