VNC具体用途,不用过多介绍了。这里只简单写一个获取服务器端画面的示例:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <rfb/rfbclient.h>
#include <rfb/rfb.h>
#include <png.h>
void saveScreenshot(rfbClient* client, const char* filename) {
std::cout << "Entering saveScreenshot function..." << std::endl;
int width = client->width;
int height = client->height;
std::cout << "Dimensions: " << width << "x" << height << std::endl;
FILE *fp = fopen(filename, "wb");
if (!fp) {
std::cerr << "Failed to open file for writing!" << std::endl;
return;
}
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
std::cout << "PNG structures initialized..." << std::endl;
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_byte** rows = (png_byte**)malloc(height * sizeof(png_byte*));
std::cout << "Processing pixels..." << std::endl;
for (int y = 0; y < height; y++) {
rows[y] = (png_byte*)malloc(3 * width * sizeof(png_byte));
for (int x = 0; x < width; x++) {
uint16_t pixel = ((uint16_t*)client->frameBuffer)[y * width + x];
uint8_t r = (pixel >> 10) & 0x1F; // 5 bits red
uint8_t g = (pixel >> 5) & 0x1F; // 5 bits green
uint8_t b = pixel & 0x1F; // 5 bits blue
// Convert from 5 bits to 8 bits
rows[y][x*3] = (r << 3) | (r >> 2);
rows[y][x*3+1] = (g << 3) | (g >> 2);
rows[y][x*3+2] = (b << 3) | (b >> 2);
}
}
std::cout << "Writing PNG..." << std::endl;
png_set_rows(png_ptr, info_ptr, rows);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for (int y = 0; y < height; y++) {
free(rows[y]);
}
free(rows);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
std::cout << "Exiting saveScreenshot function..." << std::endl;
}
rfbBool resize(rfbClient* client) {
int width = client->width;
int height = client->height;
std::cout << "Resized to " << width << "x" << height << std::endl;
client->frameBuffer = (uint8_t*)realloc(client->frameBuffer, width * height * client->format.bitsPerPixel / 8);
return TRUE;
}
char* get_password(rfbClient* client) {
return strdup("Ls1020..");
}
bool framebufferUpdated = false;
static void frameBufferUpdateCallback(rfbClient* client, int x, int y, int w, int h) {
static time_t t=0,t1;
FILE* f;
int i,j;
rfbPixelFormat* pf=&client->format;
int bpp=pf->bitsPerPixel/8;
int row_stride=client->width*bpp;
t1=time(NULL);
if(t1-t>2)
t=t1;
else
return;
if(bpp!=4 && bpp!=2) {
rfbClientLog("bpp = %d (!=4)\n",bpp);
return;
}
f=fopen("framebuffer.ppm","wb");
if(!f) {
rfbClientErr("Could not open framebuffer.ppm\n");
return;
}
fprintf(f,"P6\n# %s\n%d %d\n255\n",client->desktopName,client->width,client->height);
for(j=0;j<client->height*row_stride;j+=row_stride)
for(i=0;i<client->width*bpp;i+=bpp) {
unsigned char* p=client->frameBuffer+j+i;
unsigned int v;
if(bpp==4)
v=*(unsigned int*)p;
else if(bpp==2)
v=*(unsigned short*)p;
else
v=*(unsigned char*)p;
fputc((v>>pf->redShift)*256/(pf->redMax+1),f);
fputc((v>>pf->greenShift)*256/(pf->greenMax+1),f);
fputc((v>>pf->blueShift)*256/(pf->blueMax+1),f);
}
fclose(f);
framebufferUpdated = true;
}
int main(int argc, char *argv[]){
rfbClient* client = rfbGetClient(8, 3, 4);
client->MallocFrameBuffer = resize;
client->GetPassword = get_password;
client->serverHost = strdup("42.48.206.82");
client->serverPort = 5901;
client->GotFrameBufferUpdate = frameBufferUpdateCallback;
if (!rfbInitClient(client, nullptr, nullptr)) {
std::cerr << "Failed to initialize the client!" << std::endl;
return 1;
}
// Request a full framebuffer update from the server
std::cout << "Requesting framebuffer update..." << std::endl;
SendFramebufferUpdateRequest(client, 0, 0, client->width, client->height, FALSE);
std::cout << "Taking a screenshot..." << std::endl;
time_t t = time(NULL);
while (time(NULL)-t<50 && !framebufferUpdated) {
int n = WaitForMessage(client,50);
if(n < 0){
// client->socket==-1
break;
}
if (n==0){
// no message from server
}
if(n){
// handle message from server
if(!HandleRFBServerMessage(client))
break;
}
}
if (framebufferUpdated){
saveScreenshot(client, "screenshot.png");
}
rfbClientCleanup(client);
return 0;
}
如果需要实时更新服务器端画面,while循环就可以了。