操作系统与网络 2019-3-14

本文详细介绍动态库的创建与使用,包括通过.def文件导出函数、显式加载及使用函数指针,以及如何实现动态共享库以供多个进程共享。此外,还介绍了基于UDP协议的网络编程,涵盖库加载、套接字创建、数据收发等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.继续动态库

1.1 使用 .def 文件来引用动态库的导出库

1.新建一个空的解决方案,添加一个 MyDllLib 项目,创建一个 MyDllLib.cpp 文件,一个 MyDllLib.h 文件;
cpp 源文件

int MyAdd(int a, int b)
{
	return a+b;
}

int MySub(int a, int b)
{
	return a-b;
}

h 头文件

#ifndef _MYDLLLIB_H_
#define _MYDLLLIB_H_

int MyAdd(int a, int b);
int MySub(int a, int b);

#endif //_MYDLLLIB_H_

2.在 MyDllLib 项目的源文件中添加一个 模块定义文件.def ,可以在 代码 选项中找到,在其中添加:

LIBRARY "MyDllLib"

EXPORTS
MyAdd @1
MySub @2

3.在创建一个 Test 项目,进行动态库的引用;
main.cpp

#include <iostream>
using namespace std;

#include "../MyDllLib/MyDllLib.h"
#pragma comment(lib, "../Debug/MyDllLib.lib")

int main()
{
	cout << MyAdd(1, 10) << endl;

	return 0;
}

4.将该库的编译风格设置为C,使其可以在 .c 文件中使用;

#ifndef _MYDLLLIB_H_
#define _MYDLLLIB_H_

#ifdef __cplusplus
	extern "C" int Add(int a, int b);
	extern "C" int Sub(int a, int b);
#else
	int Add(int a, int b);
	int Sub(int a, int b);
#endif // __cplusplus

#endif //_MYDLLLIB_H_

1.2 显式运行时加载

1.这可使得我们无需调用 MyDllLib.h 以及其生成的导出库 lib ;
2.需要一个函数指针来作为函数的承接口;
3.对于 GetProcAddress 函数,第一个参数是动态库的句柄,第二个参数是函数的名称;
4.使用完动态库句柄之后我们需要将其释放掉;

#include <iostream>
using namespace std;

#include <windows.h>

// 定义一个函数指针用来作为库句柄调用函数
typedef int (*PFUNC)(int, int);

int main()
{
	HMODULE lib_handle = ::LoadLibrary(L"../Debug/MyDllLib.dll");

	if(lib_handle != 0)
	{
		PFUNC pFun = (PFUNC)::GetProcAddress(lib_handle, "MyAdd");
		cout << pFun(2, 5) << endl;

		::FreeModule(lib_handle);
		lib_handle = 0;
	}

	system("pause");
	return 0;
}
  1. c语言 文件同样适用(C语言中没有 :: 全局作用域符号);
#include <stdio.h>

#include <windows.h>

// 定义一个函数指针用来作为库句柄调用函数
typedef int (*PFUNC)(int, int);

int main()
{
	HMODULE lib_handle = LoadLibrary(L"../Debug/MyDllLib.dll");
	PFUNC pFun = 0;

	if(lib_handle != 0)
	{
		PFUNC pFun = (PFUNC)GetProcAddress(lib_handle, "Add");
		printf("%d\n", pFun(1, 5));

		FreeModule(lib_handle);
		lib_handle = 0;
	}

	return 0;
}

2.动态共享库

2.1 我们希望多个进程可以共用一个动态库,这时候我们就需要动态共享库

1.创建一个新的空白解决方案,添加一个 dll 项目,不勾选 空项目 ;
2.在源文件中添加一个 Share.cpp 源文件;

#include <stdafx.h>

int a = 0;

void SetValue(int b)
{
	a = b;
}

int GetValue()
{
	return a;
}

3.添加一个 Share.h 文件,里面装着两个函数声明;

#ifndef _SHARE_H_
#define _SHARE_H_

void SetValue(int b);
int GetValue();

#endif //_SHARE_H_

4.添加一个 模块定义文件.def ,进行动态库的函数导出;

LIBRARY SHARE

EXPORTS
GetValue @1
SetValue @2

4.生成动态库文件 Share.dll 以及导出函数文件 Share.lib ;
5.给该解决方案添加一个基于对话框的MFC应用程序,向对话框上添加两个按钮,一个 Edit 控件,并给 Edit 控件添加变量,变量类型为 Value 型,变量为 DWORD m_sValue ;
6.给 SetValue 按钮添加点击处理函数,获得 a 的值,并将 a 的值放到MessageBox上;

void CSHAREDPROCESSDlg::OnBnClickedButton2()
{
	// SetValue按钮
	m_sValue = GetValue();
	CString str;
	str.Format(_T("%d"), m_sValue);
	MessageBox(str);
}

7.给 GetValue 按钮添加点击处理函数,从对话框上取数,并将取下来的数赋值给 a ;

void CSHAREDPROCESSDlg::OnBnClickedButton1()
{
	// GetValue按钮
	UpdateData(TRUE);
	SetValue(m_sValue);
}

8.给对话框类引用动态库的导出库文件;

// 调用动态库
#include "../SharedDll/SharedDll.h"
#pragma comment(lib, "../Debug/SharedDll.lib")

9.运行该MFC应用程序,在 Edit 上输入一串数字,点击 GetValue 将a的值更改为 Edit 上的值,在点击 SetValue 按钮将a的值用MessageBox显示出来;

2.2 我们运行两个生成的exe文件,在一个上设置a的值,在另一个上获得a的值,发现获得的值并不是我们设置的a的值,这是因为我们没有将库中的变量a进行共享

1.在 Share.cpp 文件中使用 pragma data_seg 将变量a进行共享(补上一句,创建时未勾选空项目,那么我们需要在每一个源文件中引用 stdafx.h 头文件);

#include "stdafx.h"

#pragma data_seg("MySeg")
int a = 0;
#pragma data_seg()

void SetValue(int b)
{
	a = b;
}

int GetValue()
{
	return a;
}

2.在 .def 文件中添加:

LIBRARY SHARE

EXPORTS
GetValue @1
SetValue @2

SECTIONS
MySeg SHARED

3.重新生成动态库,再运行两个exe文件,即可实现在一个对话框上可以获得另一个对话框上设置的a的值;

3.网络

3.1 概念

网络是各种连在一起的可以互相通信的设备的集合。

3.2 UDP用户数据报文协议

3.3 创建一个基于UPD的客户端

1.创建一个基于UDP的客户端分为5步:加载库->创建通信接口套接字socket->将自己的信息与套接字进行绑定->收发数据->关闭套接字->卸载库;
2.新建一个空白解决方案,在其中添加一个Win32控制台应用程序,添加一个源文件 ClientMain.cpp ;
3.首先加载库: WSAStartup 函数;加载库的过程可以在该函数的帮助文档中获取,我们将示例代码复制到该文件中;
4.创建一个套接字: socket ;其第一个参数是遵循的地址规则(IPv4或者IPv6等),第二个参数是传送什么样的数据(本次选择数据报文格式),第三个参数是传输的协议(本次选择UDP);
5.将自己的信息与套接字进行绑定: bind ;首先我们需要将自己的信息存储到一个结构体中,该结构体包括要传送数据的端口号、自己遵循的IP协议、自己的IP地址;
6.传输数据: sendto ;该函数第一个参数本机的套接字,第二个参数是传送的数据的地址,第三个参数是传送的数据的大小,第四个是标记(本次置为零),第五个是需要接收端的信息(本次虚拟一个),最后一个是接收端的地址的大小(用来区别是哪一个地址结构体);
7.关闭库: WSACleanup ;

#include <iostream>
using namespace std;

#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

int main()
{
	// 1.加载库
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 2);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) 
	{

		printf("WSAStartup failed with error: %d\n", err);
		return 1;
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) 
	{
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return 1;
	}
	else
		printf("The Winsock 2.2 dll was found okay\n");

	// 2.创建套接字
	SOCKET socket_client = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(socket_client == INVALID_SOCKET)
	{
		cout << "error code: " << WSAGetLastError() << endl;
		WSACleanup();
		return -1;
	}

	// 3.绑定套接字与自己的端口
	sockaddr_in addr_client;												// 自己的信息
	addr_client.sin_family = AF_INET;										// 自己的IP地址是IPv4 还是IPv6
	addr_client.sin_port = htons(4567);										// 端口号
	addr_client.sin_addr.S_un.S_addr = inet_addr("192.168.1.25");			// 自己的IP地址
	if(SOCKET_ERROR == ::bind(socket_client, (const sockaddr*)&addr_client, sizeof(sockaddr_in)))
	{
		cout << "error code: " << WSAGetLastError() << endl;
		::closesocket(socket_client);
		WSACleanup();
		return -1;
	}

	// 4.传输数据
	char sz_buffer[1024] = {0};
	cin >> sz_buffer;
	sockaddr_in addr_server;
	addr_server.sin_family = AF_INET;
	addr_server.sin_port = htons(4568);
	addr_server.sin_addr.S_un.S_addr = inet_addr("192.168.1.26");
	int n_send_size = ::sendto(socket_client, sz_buffer, 1024, 0, (const sockaddr*)&addr_server, sizeof(sockaddr_in));
	if(n_send_size <= 0)
	{
		cout << "error code: " << WSAGetLastError() << endl;
	}

	// 5.关闭库
	WSACleanup();

	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值