1. 程式人生 > >linux下使用hiredis非同步API實現sub/pub訊息訂閱和釋出的功能

linux下使用hiredis非同步API實現sub/pub訊息訂閱和釋出的功能

本文轉載自連結:  最近使用redis的c介面——hiredis,使客戶端與redis伺服器通訊,實現訊息訂閱和釋出(PUB/SUB)的功能,我把遇到的一些問題和解決方法列出來供大家學習。        廢話不多說,先貼程式碼。 redis_publisher.h
/*************************************************************************
    > File Name: redis_publisher.h
    > Author: chenzengba
    > Mail: [email protected] 
    > Created Time: Sat 23 Apr 2016 10:15:09 PM CST
    > Description: 封裝hiredis,實現訊息釋出給redis功能
 ************************************************************************/

#ifndef REDIS_PUBLISHER_H
#define REDIS_PUBLISHER_H

#include <stdlib.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libevent.h>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <boost/tr1/functional.hpp>

class CRedisPublisher
{
public:    
    CRedisPublisher();
    ~CRedisPublisher();

    bool init();
    bool uninit();
    bool connect();
    bool disconnect();
    
    bool publish(const std::string &channel_name, 
        const std::string &message);

private:
     // 下面三個回撥函式供redis服務呼叫
    // 連接回調
    static void connect_callback(const redisAsyncContext *redis_context,
        int status);
	
	// 斷開連線的回撥
    static void disconnect_callback(const redisAsyncContext *redis_context,
        int status);

	// 執行命令回撥
    static void command_callback(redisAsyncContext *redis_context,
        void *reply, void *privdata);

    // 事件分發執行緒函式
    static void *event_thread(void *data);
    void *event_proc();

private:
     // libevent事件物件
    event_base *_event_base;
	// 事件執行緒ID
    pthread_t _event_thread;
	// 事件執行緒的訊號量
    sem_t _event_sem;
	// hiredis非同步物件
    redisAsyncContext *_redis_context;
};

#endif
redis_publisher.cpp
/*************************************************************************
    > File Name: redis_publisher.cpp
    > Author: chenzengba
    > Mail: [email protected] 
    > Created Time: Sat 23 Apr 2016 10:15:09 PM CST
    > Description: 
 ************************************************************************/
 
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include "redis_publisher.h"

CRedisPublisher::CRedisPublisher():_event_base(0), _event_thread(0),
_redis_context(0)
{
}

CRedisPublisher::~CRedisPublisher()
{
}

bool CRedisPublisher::init()
{
    // initialize the event
    _event_base = event_base_new();    // 建立libevent物件
    if (NULL == _event_base)
    {
        printf(": Create redis event failed.\n");
        return false;
    }

    memset(&_event_sem, 0, sizeof(_event_sem));
    int ret = sem_init(&_event_sem, 0, 0);
    if (ret != 0)
    {
        printf(": Init sem failed.\n");
        return false;
    }

    return true;
}

bool CRedisPublisher::uninit()
{
    _event_base = NULL;
    
    sem_destroy(&_event_sem);   
    return true;
}

bool CRedisPublisher::connect()
{
    // connect redis
    _redis_context = redisAsyncConnect("127.0.0.1", 6379);    // 非同步連線到redis伺服器上,使用預設埠
    if (NULL == _redis_context)
    {
        printf(": Connect redis failed.\n");
        return false;
    }

    if (_redis_context->err)
    {
        printf(": Connect redis error: %d, %s\n", 
            _redis_context->err, _redis_context->errstr);    // 輸出錯誤資訊
        return false;
    }

    // attach the event
    redisLibeventAttach(_redis_context, _event_base);    // 將事件繫結到redis context上,使設定給redis的回撥跟事件關聯
    
    // 建立事件處理執行緒
    int ret = pthread_create(&_event_thread, 0, &CRedisPublisher::event_thread, this);
    if (ret != 0)
    {
        printf(": create event thread failed.\n");
        disconnect();
        return false;
    }

	// 設定連接回調,當非同步呼叫連線後,伺服器處理連線請求結束後呼叫,通知呼叫者連線的狀態
    redisAsyncSetConnectCallback(_redis_context, 
        &CRedisPublisher::connect_callback);

	// 設定斷開連接回調,當伺服器斷開連線後,通知呼叫者連線斷開,呼叫者可以利用這個函式實現重連
    redisAsyncSetDisconnectCallback(_redis_context,
        &CRedisPublisher::disconnect_callback);

	// 啟動事件執行緒
    sem_post(&_event_sem);
    return true;
}

bool CRedisPublisher::disconnect()
{
    if (_redis_context)
    {
        redisAsyncDisconnect(_redis_context);
        redisAsyncFree(_redis_context);
        _redis_context = NULL;
    }

    return true;
}

bool CRedisPublisher::publish(const std::string &channel_name,
    const std::string &message)
{
    int ret = redisAsyncCommand(_redis_context, 
        &CRedisPublisher::command_callback, this, "PUBLISH %s %s", 
        channel_name.c_str(), message.c_str());
    if (REDIS_ERR == ret)
    {
        printf("Publish command failed: %d\n", ret);
        return false;
    }

    return true;
}

void CRedisPublisher::connect_callback(const redisAsyncContext *redis_context,
    int status)
{
    if (status != REDIS_OK)
    {
        printf(": Error: %s\n", redis_context->errstr);
    }
    else
    {
        printf(": Redis connected!\n");
    }
}

void CRedisPublisher::disconnect_callback(
    const redisAsyncContext *redis_context, int status)
{
    if (status != REDIS_OK)
    {
		// 這裡異常退出,可以嘗試重連
        printf(": Error: %s\n", redis_context->errstr);
    }
}

// 訊息接收回調函式
void CRedisPublisher::command_callback(redisAsyncContext *redis_context,
    void *reply, void *privdata)
{
    printf("command callback.\n");
	// 這裡不執行任何操作
}

void *CRedisPublisher::event_thread(void *data)
{
    if (NULL == data)
    {
        printf(": Error!\n");
        assert(false);
        return NULL;
    }

    CRedisPublisher *self_this = reinterpret_cast<CRedisPublisher *>(data);
    return self_this->event_proc();
}

void *CRedisPublisher::event_proc()
{
    sem_wait(&_event_sem);
	
	// 開啟事件分發,event_base_dispatch會阻塞
    event_base_dispatch(_event_base);

    return NULL;
}
redis_subscriber.h
/*************************************************************************
    > File Name: redis_subscriber.h
    > Author: chenzengba
    > Mail: [email protected] 
    > Created Time: Sat 23 Apr 2016 10:15:09 PM CST
    > Description: 封裝hiredis,實現訊息訂閱redis功能
 ************************************************************************/

#ifndef REDIS_SUBSCRIBER_H
#define REDIS_SUBSCRIBER_H

#include <stdlib.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libevent.h>
#include <string>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <boost/tr1/functional.hpp>

class CRedisSubscriber
{
public:
    typedef std::tr1::function<void (const char *, const char *, int)>         NotifyMessageFn;	// 回撥函式物件型別,當接收到訊息後呼叫回撥把訊息傳送出去
		
    CRedisSubscriber();
    ~CRedisSubscriber();
    
	bool init(const NotifyMessageFn &fn);	// 傳入回撥物件
    bool uninit();
    bool connect();
    bool disconnect();
    
    // 可以多次呼叫,訂閱多個頻道
    bool subscribe(const std::string &channel_name);
	
private:
    // 下面三個回撥函式供redis服務呼叫
    // 連接回調
    static void connect_callback(const redisAsyncContext *redis_context,
        int status);
	
	// 斷開連線的回撥
    static void disconnect_callback(const redisAsyncContext *redis_context,
        int status);

	// 執行命令回撥
    static void command_callback(redisAsyncContext *redis_context,
        void *reply, void *privdata);

    // 事件分發執行緒函式
    static void *event_thread(void *data);
    void *event_proc();
	
private:
    // libevent事件物件
    event_base *_event_base;
	// 事件執行緒ID
    pthread_t _event_thread;
	// 事件執行緒的訊號量
    sem_t _event_sem;
	// hiredis非同步物件
    redisAsyncContext *_redis_context;
	
	// 通知外層的回撥函式物件
    NotifyMessageFn _notify_message_fn;
};

#endif
redis_subscriber.cpp:
/*************************************************************************
    > File Name: redis_subscriber.cpp
    > Author: chenzengba
    > Mail: [email protected] 
    > Created Time: Sat 23 Apr 2016 10:15:09 PM CST
    > Description: 
 ************************************************************************/
 
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include "redis_subscriber.h"

CRedisSubscriber::CRedisSubscriber():_event_base(0), _event_thread(0),
_redis_context(0)
{
}

CRedisSubscriber::~CRedisSubscriber()
{
}

bool CRedisSubscriber::init(const NotifyMessageFn &fn)
{
    // initialize the event
    _notify_message_fn = fn;
    _event_base = event_base_new();    // 建立libevent物件
    if (NULL == _event_base)
    {
        printf(": Create redis event failed.\n");
        return false;
    }

    memset(&_event_sem, 0, sizeof(_event_sem));
    int ret = sem_init(&_event_sem, 0, 0);
    if (ret != 0)
    {
        printf(": Init sem failed.\n");
        return false;
    }

    return true;
}

bool CRedisSubscriber::uninit()
{
    _event_base = NULL;
    
    sem_destroy(&_event_sem);   
    return true;
}

bool CRedisSubscriber::connect()
{
    // connect redis
    _redis_context = redisAsyncConnect("127.0.0.1", 6379);    // 非同步連線到redis伺服器上,使用預設埠
    if (NULL == _redis_context)
    {
        printf(": Connect redis failed.\n");
        return false;
    }

    if (_redis_context->err)
    {
        printf(": Connect redis error: %d, %s\n", 
            _redis_context->err, _redis_context->errstr);    // 輸出錯誤資訊
        return false;
    }

    // attach the event
    redisLibeventAttach(_redis_context, _event_base);    // 將事件繫結到redis context上,使設定給redis的回撥跟事件關聯
    
    // 建立事件處理執行緒
    int ret = pthread_create(&_event_thread, 0, &CRedisSubscriber::event_thread, this);
    if (ret != 0)
    {
        printf(": create event thread failed.\n");
        disconnect();
        return false;
    }

	// 設定連接回調,當非同步呼叫連線後,伺服器處理連線請求結束後呼叫,通知呼叫者連線的狀態
    redisAsyncSetConnectCallback(_redis_context, 
        &CRedisSubscriber::connect_callback);

	// 設定斷開連接回調,當伺服器斷開連線後,通知呼叫者連線斷開,呼叫者可以利用這個函式實現重連
    redisAsyncSetDisconnectCallback(_redis_context,
        &CRedisSubscriber::disconnect_callback);

	// 啟動事件執行緒
    sem_post(&_event_sem);
    return true;
}

bool CRedisSubscriber::disconnect()
{
    if (_redis_context)
    {
        redisAsyncDisconnect(_redis_context);
        redisAsyncFree(_redis_context);
        _redis_context = NULL;
    }

    return true;
}

bool CRedisSubscriber::subscribe(const std::string &channel_name)
{
    int ret = redisAsyncCommand(_redis_context, 
        &CRedisSubscriber::command_callback, this, "SUBSCRIBE %s", 
        channel_name.c_str());
    if (REDIS_ERR == ret)
    {
        printf("Subscribe command failed: %d\n", ret);
        return false;
    }
    
    printf(": Subscribe success: %s\n", channel_name.c_str());
    return true;
}

void CRedisSubscriber::connect_callback(const redisAsyncContext *redis_context,
    int status)
{
    if (status != REDIS_OK)
    {
        printf(": Error: %s\n", redis_context->errstr);
    }
    else
    {
        printf(": Redis connected!");
    }
}

void CRedisSubscriber::disconnect_callback(
    const redisAsyncContext *redis_context, int status)
{
    if (status != REDIS_OK)
    {
		// 這裡異常退出,可以嘗試重連
        printf(": Error: %s\n", redis_context->errstr);
    }
}

// 訊息接收回調函式
void CRedisSubscriber::command_callback(redisAsyncContext *redis_context,
    void *reply, void *privdata)
{
    if (NULL == reply || NULL == privdata) {
        return ;
    }

	// 靜態函式中,要使用類的成員變數,把當前的this指標傳進來,用this指標間接訪問
    CRedisSubscriber *self_this = reinterpret_cast<CRedisSubscriber *>(privdata);
    redisReply *redis_reply = reinterpret_cast<redisReply *>(reply);
	
	// 訂閱接收到的訊息是一個帶三元素的陣列
    if (redis_reply->type == REDIS_REPLY_ARRAY &&
    redis_reply->elements == 3)
    {
        printf(": Recieve message:%s:%d:%s:%d:%s:%d\n",
        redis_reply->element[0]->str, redis_reply->element[0]->len,
        redis_reply->element[1]->str, redis_reply->element[1]->len,
        redis_reply->element[2]->str, redis_reply->element[2]->len);
		
		// 呼叫函式物件把訊息通知給外層
        self_this->_notify_message_fn(redis_reply->element[1]->str,
            redis_reply->element[2]->str, redis_reply->element[2]->len);
    }
}

void *CRedisSubscriber::event_thread(void *data)
{
    if (NULL == data)
    {
        printf(": Error!\n");
        assert(false);
        return NULL;
    }

    CRedisSubscriber *self_this = reinterpret_cast<CRedisSubscriber *>(data);
    return self_this->event_proc();
}

void *CRedisSubscriber::event_proc()
{
    sem_wait(&_event_sem);
	
	// 開啟事件分發,event_base_dispatch會阻塞
    event_base_dispatch(_event_base);

    return NULL;
}

問題1:hiredis官網沒有非同步介面的實現例子。

        hiredis提供了幾個非同步通訊的API,一開始根據API名字的理解,我們實現了跟redis伺服器建立連線、訂閱和釋出的功能,可在實際使用的時候,程式並沒有像我們預想的那樣,除了能夠建立連線外,任何事情都沒發生。         網上查了很多資料,原來hiredis的非同步實現是通過事件來分發redis傳送過來的訊息的,hiredis可以使用libae、libev、libuv和libevent中的任何一個實現事件的分發,網上的資料提示使用libae、libev和libuv可能發生其他問題,這裡為了方便就選用libevent。hireds官網並沒有對libevent做任何介紹,也沒用說明使用非同步機制需要引入事件的介面,所以一開始走了很多彎路。         關於libevent的使用這裡就不再贅述,詳情可以見libevent官網。 libevent官網:http://libevent.org/ libevent api文件:https://www.monkey.org/~provos/libevent/doxygen-2.0.1/include_2event2_2event_8h.html#6e9827de8c3014417b11b48f2fe688ae CRedisPublisher和CRedisSubscriber的初始化過程: 初始化事件處理,並獲得事件處理的例項:
_event_base = event_base_new();

在獲得redisAsyncContext *之後,呼叫
redisLibeventAttach(_redis_context, _event_base);
這樣就將事件處理和redis關聯起來,最後在另一個執行緒呼叫
event_base_dispatch(_event_base);
啟動事件的分發,這是一個阻塞函式,因此,建立了一個新的執行緒處理事件分發,值得注意的是,這裡用訊號燈_event_sem控制執行緒的啟動,意在程式呼叫
    redisAsyncSetConnectCallback(_redis_context, 
        &CRedisSubscriber::connect_callback);
    redisAsyncSetDisconnectCallback(_redis_context,
        &CRedisSubscriber::disconnect_callback);
之後,能夠完全捕捉到這兩個回撥。

問題2 奇特的‘ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context’錯誤

        有些人會覺得這兩個類設計有點冗餘,我們發現CRedisPublisher和CRedisSubscriber很多邏輯是一樣的,為什麼不把他們整合到一起成一個類,既能夠釋出訊息也能夠訂閱訊息。其實一開始我就是這麼幹的,在使用的時候發現,用同個redisAsynContex *物件進行訊息訂閱和釋出,與redis服務連線會自動斷開,disconnect_callback回撥會被呼叫,並且返回奇怪的錯誤:ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context,因此,不能使用同個redisAsyncContext *物件實現釋出和訂閱。這裡為了減少設計的複雜性,就將兩個類的邏輯分開了。         當然,你也可以將相同的邏輯抽象到一個基類裡,並實現publish和subscribe介面。

問題3 相關依賴的庫

        編譯之前,需要安裝hiredis、libevent和boost庫,我是用的是Ubuntu x64系統。 hiredis官網:https://github.com/redis/hiredis 下載原始碼解壓,進入解壓目錄,執行make && make install命令。 libevent官網:http://libevent.org/下載最新的穩定版 解壓後進入解壓目錄,執行命令 ./configure -prefix=/usr sudo make && make install boost庫:直接執行安裝:sudo apt-get install libboost-dev 如果你不是用std::tr1::function的函式物件來給外層通知訊息,就不需要boost庫。你可以用介面的形式實現回撥,把介面傳給CRedisSubscribe類,讓它在接收到訊息後呼叫介面回撥,通知外層。

問題4 如何使用

        最後貼出例子程式碼。 publisher.cpp,實現釋出訊息:
/*************************************************************************
    > File Name: publisher.cpp
    > Author: chenzengba
    > Mail: [email protected] 
    > Created Time: Sat 23 Apr 2016 12:13:24 PM CST
 ************************************************************************/

#include "redis_publisher.h"

int main(int argc, char *argv[])
{
    CRedisPublisher publisher;

    bool ret = publisher.init();
    if (!ret) 
    {
        printf("Init failed.\n");
        return 0;
    }

    ret = publisher.connect();
    if (!ret)
    {
        printf("connect failed.");
        return 0;
    }

    while (true)
    {
        publisher.publish("test-channel", "Test message");
        sleep(1);
    }

    publisher.disconnect();
    publisher.uninit();
    return 0;
}

subscriber.cpp實現訂閱訊息:
/*************************************************************************
    > File Name: subscriber.cpp
    > Author: chenzengba
    > Mail: [email protected] 
    > Created Time: Sat 23 Apr 2016 12:26:42 PM CST
 ************************************************************************/

#include "redis_subscriber.h"

void recieve_message(const char *channel_name,
    const char *message, int len)
{
    printf("Recieve message:\n    channel name: %s\n    message: %s\n",
        channel_name, message);
}

int main(int argc, char *argv[])
{
    CRedisSubscriber subscriber;
    CRedisSubscriber::NotifyMessageFn fn = 
        bind(recieve_message, std::tr1::placeholders::_1,
        std::tr1::placeholders::_2, std::tr1::placeholders::_3);

    bool ret = subscriber.init(fn);
    if (!ret)
    {
        printf("Init failed.\n");
        return 0;
    }

    ret = subscriber.connect();
    if (!ret)
    {
        printf("Connect failed.\n");
        return 0;
    }

    subscriber.subscribe("test-channel");

    while (true)
    {
        sleep(1);
    }

    subscriber.disconnect();
    subscriber.uninit();

    return 0;
}

關於編譯的問題:在g++中編譯,注意要加上-lhiredis -levent引數,下面是一個簡單的Makefile:
EXE=server_main client_main
CC=g++
FLAG=-lhiredis -levent
OBJ=redis_publisher.o publisher.o redis_subscriber.o subscriber.o

all:$(EXE)

$(EXE):$(OBJ)
	$(CC) -o publisher redis_publisher.o publisher.o $(FLAG)
	$(CC) -o subscriber redis_subscriber.o subscriber.o $(FLAG)

redis_publisher.o:redis_publisher.h
redis_subscriber.o:redis_subscriber.h

publisher.o:publisher.cpp
	$(CC) -c publisher.cpp

subscriber.o:subscriber.cpp
	$(CC) -c subscriber.cpp
clean:
	rm publisher subscriber *.o


致謝: redis非同步API使用libevent:http://www.tuicool.com/articles/N73uuu 

相關推薦

linux使用hiredis非同步API實現sub/pub訊息訂閱釋出功能

本文轉載自連結:  最近使用redis的c介面——hiredis,使客戶端與redis伺服器通訊,實現訊息訂閱和釋出(PUB/SUB)的功能,我把遇到的一些問題和解決方法列出來供大家學習。        廢話不多說,先貼程式碼。 redis_publisher.

Linuxmysql基於MyCat實現主從復制讀寫分離

mycat1.1 MyCat介紹及應用場景MyCat介紹MyCat是一個開源的分布式數據庫系統,是一個實現了MySQL協議的服務器,前端用戶可以把它看作是一個數據庫代理,用MySQL客戶端工具和命令行訪問,而其後端可以用MySQL原生協議與多個MySQL服務器通信,也可以用JDBC協議與大多數主流數據庫服務器

LinuxWi-Fi的實現:wireless_toolswpa_supplicant

erl 密碼 fig 而是 tar.gz 方式 控制 nec dbm 轉載於:https://www.cnblogs.com/lidabo/p/6069455.html 平臺為hi35XX,在Liunx下借助wireless_tools和wpa_supplicant(因為現

Linux的簡易shell實現

Linux系統的shell作為作業系統的外殼,為使用者提供使用作業系統的介面。 它是命令語言、命令解釋程式及程式設計語言的統稱。 相當於bash的一個子程序,父程序等待,子程序進行程式替換。 shell充當一個橋樑:將使用者的命令翻譯給核心(kernel)處理;同時,將核心的

Linux網路socket程式設計——實現伺服器(select)與多個客戶端通訊

Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊 置頂 2017年06月23日 14:44:37 閱讀數:3225 標籤: socket程式設計伺服器與多個客戶端通epoll多路複用C語言網路程式設計 更多

linux操作svn,實現根據時間段檢視某個指定使用者提交的記錄

svn log -v -r {2018-9-10}:{2018-9-25} | sed -n '/danni/,/--$/ p' 其中: -r {2018-9-10}:{2018-9-25}:通過-r來指定時間段 -v:表示顯示詳細資訊 sed -n '/danni/,/--$/

Linux進度條的實現(加彩色版本)

一:進度條 關於進度條不用我多說,當我們在安裝程式或者軟體時通常會看到軟體安裝進度,而這個給我以視覺感受的進度表示,通常被叫做進度條。 二:進度條需要的知識儲備 緩衝區: 對於緩衝區這個概念我們其實並不

Linux用c語言實現發送http請求 方式可以Get或者Post例程參考

sockaddr select sleep online 創建 線程終止 index -s lse [1].[代碼] Linux下用c語言實現發送http請求 方式可以Get或者Post 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10 11 12 1

Linux用c語言實現傳送http請求 方式可以Get或者Post例程參考

[1].[程式碼] Linux下用c語言實現傳送http請求 方式可以Get或者Post 跳至 [1] ? 1 2

Linux併發伺服器的實現

實現併發伺服器的方式有多種,下面說一下我瞭解到的幾種解決方案。 方案一:多程序併發伺服器 主程序監聽、accept()連線,子程序負責處理業務邏輯和流的讀取。            缺點:程序需

Linux安裝Redis並實現遠端連線,Redis Desktop Manager視覺化連線

1.下載redis redis不是安裝包,例如tomcat,mysql等都是安裝包直接解壓就可以使用,redis是原始檔,需要用編譯後才可以使用。 2.使用xftp把壓縮包拖入到root/redis/資料夾下,並解壓 tar -zxvf redis-5.0.0.

Linux用c語言實現傳送http請求

前言 在linux下,使用socket進行程式設計,需要到伺服器上進行獲取資料,伺服器使用的php程式設計,需要使用http的方式進行獲取資料。 程式碼 #include <stdio.h> #include <string.h&

linux使用crontab如何實現mysql資料庫每天自動備份定時備份

直接上教程,基本上出現的問題都在下面了; 首先檢查你的伺服器是否安裝了crontab,命令如下: 命令: crontab       如果提示-bash: crontab:commandnot fo

live555在Linux最簡單地實現實時流媒體點播

通過Live555交叉編譯後執行發現,上面實現的流媒體實時通過檔案伺服器的檔案點播,沒有相關的流媒體實現方式, 但在Linux下,可以通過某些技巧實現Live555伺服器實時流媒體伺服器,並且是傻瓜式的,簡易程度不需要修改Live555下面一行程式碼。 首先,需要

Linux如何用C實現MD5加密

md5典型應用是對一段資訊(Message)產生資訊摘要(Message-Digest),以防止被篡改。比如,在UNIX下有很多軟體在下載的時候都有一個檔名相同,副檔名為.md5的檔案,在這個檔案中通常只有一行文字,大致結構如:MD5 (tanajiya.tar.gz)

linux利用openssl來實現證書的頒發(詳細步驟)

1、首先需要安裝openssl,一個開源的實現加解密和證書的專業系統。在centos下可以利用yum安裝。 2、openssl的配置檔案是openssl.cnf,我們一般就是用預設配置就可以。如果證書有特殊要求的話,可以修改配置適應需求。這樣必須把相關的檔案放到配置檔

Linux通用掃描器API——SANE( Scanner Access Now Easy)

一、SANE簡介 SANE( Scanner Access Now Easy),是一個應用程式程式設計介面(API),它提供給任何光柵影象掃描器硬體標準化的訪問(平板掃描器,手持式掃描器,視訊和靜止相機,影象採集卡等。 )。該API是公共領域,它的討論和發展,是對所

Linux簡易web伺服器實現

今天突然對http的web伺服器感興趣了,就研究了一下,發現linux下的web伺服器就是一個socket程式設計的伺服器端,而我們用的ie,chrome等瀏覽器就是客戶端,只不過傳送和接收資料按照http網頁格式,就相當於對資料進行了封裝,相當於加上了檔案頭和檔案

linuxsocket程式設計 select實現非阻塞模式多臺客戶端與伺服器通訊

select函式原型如下: int select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); select系統呼叫是用來讓我們的程式

Linux使用libevent庫實現伺服器端程式設計

一、背景 TCP伺服器端一般用到非阻塞Socket、IO複用,Linux可以支援epoll、select,而Windows支援select、IOCP,考慮平臺適用性,需要對IO事件進行封裝相容; 二、相關知識 2.1 事件驅動(I/O複用) 服務端常用到的 select