我正在尝试了解 UDP 打洞,但我不太明白。从概念上看,这似乎很简单,但当我付诸实践时,我却无法做到这一点。据我了解,有一个公共服务器,我们称之为打孔服务器。客户端向打孔服务器发出请求(这是公开的)。打孔服务器会输出刚刚发出请求的客户端的公共 IP 和端口。只要该端口打开,那么基本上任何随机客户端都可以使用该特定端口和 IP 向该客户端发出请求?
我想我遇到的问题是,客户端能够向服务器发出请求。服务器能够在该公共端口和 IP 上将数据发送回客户端,但是当另一个客户端尝试使用相同的端口和 IP 向该客户端发送请求时,它不会通过,这就是让我困惑的地方。如果服务器可以发出请求,为什么另一个随机客户端不能发出该请求?
我想知道这个问题有一段时间了,甚至有必要检查我自己的库中的指针是否有效。我是否应该期望用户传递正确的指针,因为如果他们使用该库,这是他们的工作?
例如,如果我有一个分配并返回结构的库
struct some_context{
uintptr_t somedata;
};
struct some_context* createsomecontext(void){
return malloc(sizeof(struct some_context));
}
Run Code Online (Sandbox Code Playgroud)
但后来我想对这个结构进行操作
void dosomethingwithsomecontext(struct some_context* ctx){
//which is more valid here?
assert(ctx);
//or
if(!ctx)
return;
//do something with ctx
}
Run Code Online (Sandbox Code Playgroud)
调用断言或检查结构是否有效并如果无效则返回更有意义吗?我是否应该不去检查指针而只是假设用户会做正确的事情?清理也是一样
void destroysomecontext(struct some_context* ctx){
//Which is more valid?
assert(ctx);
//or
if(!ctx)
return;
//do cleanup
}
Run Code Online (Sandbox Code Playgroud)
什么比较合适?断言,如果,或两者都不?同样,如果我什至编写一个函数来操作字符串?
void dosomestringoperation(char* str){
assert(str);
//or
if(!str)
return;
}
Run Code Online (Sandbox Code Playgroud)
图书馆应该做这些检查吗?至少在用户模式下,我可以在内核中理解,因为每个设备都可以访问全局内存,并且可能因不检查而导致崩溃,但这是否意味着即使用户模式应用程序也应该检查安全/健全的原因?
我不确定这是否可能由于结构填充和对齐而实现,但是假设您通过将结构对齐到 4/8 字节来解决这一问题,是否可以在结构上进行位移,就好像它是单个变量一样?
我想要做的是获取一个字符串(最多 8 个字节)并将其移入 64 位变量的高位。
就像我这样做:
#include <stdint.h>
#include <string.h>
void shiftstr(uint64_t* t,char* c,size_t len){
memcpy(t, c, len);
//now *t==0x000000617369616b
*t<<=(sizeof(uint64_t)-len)*8;
//now *t==0x617369616b000000
}
int main(){
uint64_t k = 0;
char n[] = "kaisa";
shiftstr(&k, n,strlen(n));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这工作得很好,但是如果我有,而不是 a uint64_t, 二uint32_t,作为单独的变量或结构怎么办?
#include <stdint.h>
#include <string.h>
struct U64{
uint32_t x;
uint32_t y;
};
void shiftstrstruct(struct U64* t, char* c, size_t len){
memcpy(t, c, len);
/*
At this point I think
x == 0x7369616b …Run Code Online (Sandbox Code Playgroud) 我正在尝试绘制蜂窝形状的六边形网格。到目前为止,我可以将其绘制为矩形,但我不知道如何将 for 循环转换为蜂窝形状。
这就是我目前拥有的
<html>
<body>
<canvas width='1080' height='720' id='hexmap'></canvas>
</body>
<script>
window.addEventListener('DOMContentLoaded', (event) => {
var canvas = document.getElementById('hexmap');
var hexHeight,
hexRadius,
hexRectangleHeight,
hexRectangleWidth,
hexagonAngle = 0.523598776, // 30 degrees in radians
sideLength = 36,
boardWidth = 10,
boardHeight = 10;
hexHeight = Math.sin(hexagonAngle) * sideLength;
hexRadius = Math.cos(hexagonAngle) * sideLength;
hexRectangleHeight = sideLength + 2 * hexHeight;
hexRectangleWidth = 2 * hexRadius;
var ctx = canvas.getContext('2d');
ctx.fillStyle = "#000000";
ctx.strokeStyle = "#CCCCCC";
ctx.lineWidth = 1;
drawBoard(ctx, boardWidth, boardHeight); …Run Code Online (Sandbox Code Playgroud)我有点困惑试图理解这里发生的事情。如果一个类对象调用一个方法,然后该方法随后销毁该对象,那么该方法不应该返回,并且应该立即销毁该对象并立即调用析构函数。对吗?但相反,代码只是崩溃了。那么,是否不允许对象调用删除自身的方法?我假设从调用堆栈的工作原理来看,指向对象的指针将被销毁,因此当函数返回到调用者时,在进一步调用调用堆栈时指针不再有效?
class Foo
{
public:
virtual void Run()
{
printf("Entering callback\n");
RunSomeCallback();
printf("We're back from callback\n");
}
virtual void RunSomeCallback() = 0;
virtual ~Foo()
{
printf("We're Destroyed\n");
}
};
Foo* f = nullptr;
void DestroyFoo();
class Bar : public Foo
{
public:
virtual void RunSomeCallback()
{
printf("Inside callback\n");
DestroyFoo();
}
};
void DestroyFoo()
{
printf("Deleting foo\n");
delete f;
}
int main()
{
f = new Bar();
f->Run();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后,当我使用shared_ptr运行代码时,行为似乎发生了变化,但在这种情况下,析构函数在打印“我们从回调中返回”之前被调用,代码运行,但这是否是未定义的行为?
class Foo
{
public:
virtual void Run()
{
printf("Entering …Run Code Online (Sandbox Code Playgroud) 我有一个全局映射对象,其中包含一个 ID 和一个类对象,但我不明白为什么调用映射中对象的析构函数。
#include <map>
#include <iostream>
#include <cassert>
#include <chrono>
#include <thread>
class TestMapObject{
private:
std::string m_sName;
public:
TestMapObject(const std::string& sName){
std::cout << "Constructor called" << std::endl;
m_sName = sName;
}
~TestMapObject(){
std::cout << "Destructor called" << std::endl;
}
const std::string& GetName(){
return m_sName;
}
};
namespace Test{
enum ETestMapKeyId{
k_ETestMapKeyNone = 0,
k_ETestMapKeyFirst,
k_ETestMapKeySecond,
};
std::map<ETestMapKeyId, TestMapObject> g_tMap;
TestMapObject* GetMapObjectById(ETestMapKeyId eID){
auto itFound = g_tMap.find(eID);
assert(itFound != g_tMap.end());
return &itFound->second;
}
}
int main(){
Test::g_tMap.insert(std::pair<Test::ETestMapKeyId,TestMapObject>(Test::k_ETestMapKeyFirst,TestMapObject("Alice")));
Test::g_tMap.insert(std::pair<Test::ETestMapKeyId,TestMapObject>(Test::k_ETestMapKeySecond,TestMapObject("Mocha")));
//destructor gets …Run Code Online (Sandbox Code Playgroud)