当前位置:  编程技术>c/c++/嵌入式

实现posix消息队列示例分享

    来源: 互联网  发布时间:2014-10-23

    本文导语:  mqueue.h 代码如下:////  mqueue.h//  UNIX_C////  Created by 周凯 on 14-2-9.//  Copyright (c) 2014年 zk. All rights reserved.// #ifndef __PS_MQUEUE_H#define __PS_MQUEUE_H #include #include typedef struct mq_info     *mqd_t;typedef struct mq_attr    mq_attr; #ifdef __cplusplusext...

mqueue.h

代码如下:

//
//  mqueue.h
//  UNIX_C
//
//  Created by 周凯 on 14-2-9.
//  Copyright (c) 2014年 zk. All rights reserved.
//

#ifndef __PS_MQUEUE_H
#define __PS_MQUEUE_H

#include
#include

typedef struct mq_info     *mqd_t;
typedef struct mq_attr    mq_attr;

#ifdef __cplusplus
extern "C" {
#endif

    mqd_t   mq_open(const char *name, int flag, .../*mode_t mode, struct mq_attr *attr*/);
    int     mq_close(mqd_t mqdes);
    int     mq_unlink(const char *name);

    int     mq_getattr(mqd_t mqdes,mq_attr *attr);
    int     mq_setattr(mqd_t mqdes,const mq_attr *attr,mq_attr *old);

    int     mq_send(mqd_t mqdes,const char *ptr,size_t len,unsigned int prio);
    int     mq_receive(mqd_t mqdes,char *ptr,size_t len,unsigned int *priop);

   
    //
    void    mq_info_test(mqd_t mqdes);

#ifdef __cplusplus
}
#endif
#endif

多进程,多线程创建同一个队列测试

代码如下:

#include
#include

void *create_mq(void *name){
    mqd_t mq;
    mq = mq_open("/tmp/mqfile", O_CREAT,FILE_MODE,0);

    if (mq == (mqd_t) -1) {
        err_ret(errno, "mq_open() error");
        return 0;
    }

    mq_info_test(mq);

    mq_close(mq);

    return 0;
}

int main(){

    mq_unlink("/tmp/mqfile");

    if (Fork() == 0) {
        create_mq("/tmp/mqfile");
        exit(0);
    }

    Create_detach_thread(create_mq, "/tmp/mqfile");
    Create_detach_thread(create_mq, "/tmp/mqfile");

    sleep(50);

    //mq_unlink("/tmp/mqfile");

    return 0;
}

测试结果

代码如下:

create,start create...
create,start init...
exists,wait get...
exists,wait get...
create,end init...
mq_hdr.mqh_free:116 bytes
msghdr size:268 bytesmap file size:3332 bytes
next msg offset and msg length:
[384,0];[652,0];[920,0];[1188,0];[1456,0];
[1724,0];[1992,0];[2260,0];[2528,0];exists,start get...
[2796,0];
[3064,0];[0,0];
end,start get...
exists,start get...
mq_hdr.mqh_free:116 bytes
msghdr size:268 bytesmap file size:3332 bytes
next msg offset and msg length:
[384,0];[652,0];[920,0];[1188,0];[1456,0];
[1724,0];[1992,0];[2260,0];[2528,0];[2796,0];
[3064,0];[0,0];
end,start get...
mq_hdr.mqh_free:116 bytes
msghdr size:268 bytesmap file size:3332 bytes
next msg offset and msg length:
[384,0];[652,0];[920,0];[1188,0];[1456,0];
[1724,0];[1992,0];[2260,0];[2528,0];[2796,0];
[3064,0];[0,0];
Program ended with exit code: 0

属性设置、获取测试

代码如下:

#include
#include

void print_attr(mq_attr *attr){
    assert(attr);

    err_msg(" mq_attr mq_flag:0x%0x"
            " mq_curmsgs:%d"
            " mq_msgsize:%d"
            " mq_maxmsg:%d"
            ,attr->mq_flags
            ,attr->mq_curmsgs
            ,attr->mq_msgsize
            ,attr->mq_maxmsg);
}

void *create_mq(void *name){
    pthread_t tid;
    mq_attr attr,old;
    mqd_t mq;
    int flag;

    flag = O_CREAT;

    tid = pthread_self();

    if ((long)tid % 2 != 0) {
        flag = O_NONBLOCK;
    }

    mq = mq_open("/tmp/mqfile", flag | O_CREAT,FILE_MODE,0);

    if (mq == (mqd_t) -1) {
        err_ret(errno, "mq_open() error");
        return 0;
    }

    if ((long)tid % 2 == 0) {
        attr.mq_flags = O_NONBLOCK;
        mq_setattr(mq, &attr, &old);
    }
    else
        mq_getattr(mq, &old);

    print_attr(&old);

    //mq_info_test(mq);

    mq_close(mq);

    return 0;
}

int main(){
    pid_t pid;

    mq_unlink("/tmp/mqfile");

    if ((pid=Fork()) == 0) {
        create_mq("/tmp/mqfile3");
        Create_detach_thread(create_mq, "/tmp/mqfile1");
        Create_detach_thread(create_mq, "/tmp/mqfile2");
        sleep(1);
        exit(0);
    }

    Create_detach_thread(create_mq, "/tmp/mqfile1");
    Create_detach_thread(create_mq, "/tmp/mqfile2");
    create_mq("/tmp/mqfile3");

    wait(0);

    sleep(5);

    //mq_unlink("/tmp/mqfile");

    return 0;
}

测试注册通知规则

代码如下:

#include
#include

int main(){
    pid_t pid;
    Init_wait();
    mqd_t mq;

    sigevent_t sige;

    mq_unlink("/tmp/mqfile");
    mq = mq_open("/tmp/mqfile", O_CREAT,FILE_MODE,0);

    Signal(SIGCHLD, SIG_DFL);

    if (mq == (mqd_t) -1) {
        err_sys(errno, "mq_open() error");
    }
    if ((pid=Fork()) == 0) {

        if (mq_notify(mq, &sige) == -1)
            err_ret(errno, "mq_notify() error");
        Tell_parent();

        Wait_parent();

        End_wait();
        sleep(1);
        exit(0);
    }

    Wait_child();
    /*子进程已注册,测试是否能注册、取消通知*/
    if (mq_notify(mq, 0) == -1)
        err_ret(errno, "mq_notify() error");
    if (mq_notify(mq, &sige) == -1)
        err_ret(errno, "mq_notify() error");
    Tell_child(pid);
    End_wait();

    wait(0);

    sleep(1);
    /*子进程已结束,测试是否能注册通知*/
    if (mq_notify(mq, &sige) == -1)
        err_ret(errno, "mq_notify() error");

    //mq_unlink("/tmp/mqfile");

    return 0;
}

mqueue.c

代码如下:

//
//  File.c
//  UNIX_C
//
//  Created by 周凯 on 14-2-9.
//  Copyright (c) 2014年 zk. All rights reserved.
//

#include "mqueue.h"
#include

#if !defined(_LINUX_)
#define va_mode_t   int
#else
#define va_mode_t   mode_t
#endif

typedef struct mq_info  mq_info;
typedef struct mq_hdr   mq_hdr;
//typedef struct mq_attr  mq_attr;
typedef struct mq_msg   mq_msg;

struct mq_hdr{
    mq_attr mqh_attr;
    long    mqh_head;
    long    mqh_free;

    pthread_cond_t  mqh_conn;
    pthread_mutex_t mqh_mutex;
    sigevent_t      mqh_sigevent;
    pid_t   mqh_pid;
};

struct mq_msg{
    long    msg_next;/*从映射内存的地址起,到下一个消息的偏移值*/
    ssize_t msg_len;
    int     msg_prio;
};

struct mq_info{
    mq_hdr *mqi_hdr;
    long long   mqi_magic;
    int     mqi_flag;
};

#define MQ_MAXMSG   12
#define MQ_MSGSIZE  256
#define MQ_MAGIC    0x9235167840
/*
 防止以下情况:
    一个进程或线程以创建模式打开一个队列,
    随后CPU切换当前进程或线程到另一个正
    在打开此前创建的队列,但是该队列并未
    初始化完毕,故使用一个记录锁加一个线
    程锁,进行同步。
 注:
    该实现不是异步调用安全,即不能在信号处理函数中调用队列打开(创建)函数
 */
#define MQ_LOCK_FILE    "/tmp/mq_lock_file"
static struct mq_attr def_attr = {0,MQ_MAXMSG,MQ_MSGSIZE,0};
static pthread_once_t __mq_once = PTHREAD_ONCE_INIT;
static pthread_mutex_t __mq_lock;
static pthread_key_t __mq_key;

static void __mq_once_init();
static int  __mq_get_filelock();
static void *__mq_mmap_file(int fd,mq_attr *attr);
static int  __mq_init_mmap(void *ptr,mq_attr *attr);
static void __mq_unmap(const char *name,void *ptr);

 

static void __mq_once_init(){
    pthread_mutexattr_t mattr;

    Pthread_mutexattr_init(&mattr);
    Pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
    Pthread_mutex_init(&__mq_lock, &mattr);
    Pthread_mutexattr_destroy(&mattr);

    Pthread_key_create(&__mq_key, 0);
}

static int  __mq_get_filelock(){
    int fd,tmp;

    Pthread_mutex_lock(&__mq_lock);
    if ((fd = (int)Pthread_getspecific(__mq_key)) == 0) {
        fd = open(MQ_LOCK_FILE, O_CREAT | O_EXCL | O_WRONLY, FILE_MODE);
        if (fd == -1 && errno != EEXIST)
            err_sys(errno, "mq_open(),__mq_get_filelock() error");
        else
            fd =Open(MQ_LOCK_FILE, O_WRONLY, 0);
        if (fd == 0) {
            tmp = Open(MQ_LOCK_FILE, O_WRONLY, 0);
            close(fd);
            fd = tmp;
        }
        Pthread_setspecific(__mq_key, (void*)fd);
    }
    Pthread_mutex_unlock(&__mq_lock);

    return fd;
}

static void *__mq_mmap_file(int fd,mq_attr *attr){
    size_t filesize;
    void *ptr;

    if (attr == 0) {
        attr = &def_attr;
    }

    if (attr->mq_maxmsg mq_msgsize mq_msgsize, sizeof(long)))*attr->mq_maxmsg;

   
    if(lseek(fd, filesize - 1, SEEK_SET)mq_maxmsg mq_msgsize mqh_attr.mq_flags = 0;
    mqhdr->mqh_attr.mq_curmsgs = 0;
    mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
    mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;

    flag = pthread_condattr_init(&cattr);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_cond_init(&mqhdr->mqh_conn, &cattr);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_condattr_destroy(&cattr);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_mutexattr_init(&mattr);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_mutex_init(&mqhdr->mqh_mutex, &mattr);
    if (flag) {
        errno = flag;
        return -1;
    }

    flag = pthread_mutexattr_destroy(&mattr);
    if (flag) {
        errno = flag;
        return -1;
    }

    index = mqhdr->mqh_free = sizeof(mq_hdr);
    mqmsg = (mq_msg*)(tmp+index);

    for (i = 0; i < attr->mq_maxmsg - 1; i++) {
        mqmsg->msg_next = sizeof(mq_msg) + ALIGN_VAL(attr->mq_msgsize, sizeof(long)) + index;
        index = mqmsg->msg_next;
        mqmsg ++;
        //mqmsg = (mq_msg*)(tmp+index);
    }
    mqmsg->msg_next = 0;

    return 0;
}

 

mqd_t   mq_open(const char *name,int flag,...){
    int fd, nonblock, lockfile_fd, err;
    void *ptr;
    mq_attr *mqattr;
    mqd_t mqdesc;
    stat_t filestat;

    debug_assert("Invalid pointer", "mq_open()", name);

    Pthread_once(&__mq_once, __mq_once_init);

    nonblock = flag & O_NONBLOCK;
    mqattr = NULL;
    mqdesc = NULL;
    ptr = MAP_FAILED;
__again:
    if (flag & O_CREAT) {
        va_list vp;
        mode_t mode;

        /*分析可变参数*/
        va_start(vp, flag);
        mode = va_arg(vp, va_mode_t);
        mqattr = va_arg(vp, mq_attr *);
        va_end(vp);

        Pthread_mutex_lock(&__mq_lock);
        lockfile_fd = __mq_get_filelock();
        write_lock_wait(lockfile_fd, SEEK_SET, 0, 0);

        fd = open(name, flag | O_CREAT | O_EXCL | O_RDWR, mode);
        if (fd < 0) {
            /*如果指定了O_EXCL,并且文件已存在,则等待其他进程或线程完成初始化*/
            if (errno == EEXIST && (flag & O_EXCL) == 1) {
                return (mqd_t)-1;
            }
            goto __exists_wait_init;
        }
        /*初始化内存映射文件*/

        err_msg("create,start init...");
        /*初始化映射文件大小(注意必须使文件长度达到映射的大小),且映射文件到内存*/
        ptr = __mq_mmap_file(fd, mqattr);
        //sleep(1);
        if (ptr == MAP_FAILED) {
            goto __err;
        }

        /*初始化映射内存的内容*/
        if (__mq_init_mmap(ptr, mqattr) < 0) {
            goto __err;
        }

        mqdesc = (mqd_t)calloc(1, sizeof(mq_hdr));
        if (mqdesc == 0) {
            goto __err;
        }

        mqdesc->mqi_hdr = (mq_hdr*)ptr;
        mqdesc->mqi_flag = nonblock;
        mqdesc->mqi_magic = MQ_MAGIC;

        err_msg("create,end init...");

        file_unlock(lockfile_fd, SEEK_SET, 0, 0);
        Pthread_mutex_unlock(&__mq_lock);

        return mqdesc;
    }
__exists_wait_init:
    fd = open(name, O_RDWR, 0);
    if (fd < 0 ) {
        if (errno == ENOENT && (flag & O_CREAT)) {
            goto __again;
        }
        goto __err;
    }

    err_msg("exists,start get...");

    if (stat(name, &filestat) == -1) {
        if (errno == ENOENT && (flag & O_CREAT)) {
            goto __again;
        }
        goto __err;
    }

    ptr = mmap(0, (size_t)filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

    if (ptr == MAP_FAILED) {
        goto __err;
    }

    mqdesc = (mqd_t)calloc(1, sizeof(mq_hdr));
    if (mqdesc == 0) {
        goto __err;
    }

    mqdesc->mqi_hdr = (mq_hdr*)ptr;
    mqdesc->mqi_flag = nonblock;
    mqdesc->mqi_magic = MQ_MAGIC;

    close(fd);

    file_unlock(lockfile_fd, SEEK_SET, 0, 0);
    Pthread_mutex_unlock(&__mq_lock);

    err_msg("end,start get...");

    return mqdesc;

__err:
    file_unlock(lockfile_fd, SEEK_SET, 0, 0);
    Pthread_mutex_unlock(&__mq_lock);

    err = errno;
    __mq_unmap(name, ptr);
    close(fd);
    if (mqdesc)
        free(mqdesc);
    errno = err;
    return (mqd_t)-1;
}

int     mq_close(mqd_t mqdes){
    size_t filesize;
    mq_attr *mattr;
    int flag;

    assert(mqdes);

    if (mqdes->mqi_magic != MQ_MAGIC) {
        errno = EBADF;
        return -1;
    }

    mattr = &mqdes->mqi_hdr->mqh_attr;
    filesize = mattr->mq_maxmsg * (sizeof(mq_msg)* ALIGN_VAL(mattr->mq_msgsize, sizeof(long))) + sizeof(mq_hdr);
    flag = munmap((void*)mqdes->mqi_hdr, filesize);

    mqdes->mqi_magic = 0;
    free(mqdes);

    return flag;
}

int     mq_unlink(char const *name){
    assert(name);
    return unlink(name);
}

int     mq_getattr(mqd_t mqdes,mq_attr *attr){
    int flag;
    mq_attr *tmp;

    assert(mqdes);
    assert(attr);

    if (mqdes->mqi_magic != MQ_MAGIC) {
        errno = EBADF;
        return -1;
    }

    tmp = &mqdes->mqi_hdr->mqh_attr;

    /*防止其他进程或线程在改变属性值*/
    flag = pthread_mutex_lock(&mqdes->mqi_hdr->mqh_mutex);
    if (flag > 0) {
        errno = flag;
        return -1;
    }

    bcopy(&mqdes->mqi_hdr->mqh_attr, attr, sizeof(mq_attr));
    attr->mq_flags = mqdes->mqi_flag;

    flag = pthread_mutex_unlock(&mqdes->mqi_hdr->mqh_mutex);
    if (flag > 0) {
        errno = flag;
        return -1;
    }

    return 0;
}

int     mq_setattr(mqd_t mqdes,const mq_attr *attr,mq_attr *old){
    int flag;
    mq_attr *tmp;

    assert(mqdes);
    assert(attr);

    if (mqdes->mqi_magic != MQ_MAGIC) {
        errno = EBADF;
        return -1;
    }

    tmp = &mqdes->mqi_hdr->mqh_attr;

    /*防止其他进程或线程在读取属性值*/
    flag = pthread_mutex_lock(&mqdes->mqi_hdr->mqh_mutex);
    if (flag > 0) {
        errno = flag;
        return -1;
    }
    if (old != NULL) {
        bcopy(&mqdes->mqi_hdr->mqh_attr, old, sizeof(mq_attr));
        old->mq_flags = mqdes->mqi_flag;
    }
    /*创建后,只有文件标识可以改变*/
    //bcopy(attr, &mqdes->mqi_hdr->mqh_attr, sizeof(mq_attr));

    /*只有O_NONBLOCK标志可以存储*/
    if (attr->mq_flags & O_NONBLOCK) {
        mqdes->mqi_flag |= O_NONBLOCK;
    }
    else {
        mqdes->mqi_flag &= ~O_NONBLOCK;
    }

    flag = pthread_mutex_unlock(&mqdes->mqi_hdr->mqh_mutex);
    if (flag > 0) {
        errno = flag;
        return -1;
    }

    return 0;
}

int     mq_notify(mqd_t mqdes,const struct sigevent *notification){
    sigevent_t *old;
    pid_t pid;
    int flag;

    assert(mqdes);

    if (mqdes->mqi_magic != MQ_MAGIC) {
        errno = EBADF;
        return -1;
    }

    flag = pthread_mutex_lock(&mqdes->mqi_hdr->mqh_mutex);
    if (flag > 0) {
        errno = flag;
        return -1;
    }

    pid = mqdes->mqi_hdr->mqh_pid;

    /*已设置*/
    if (pid != 0) {
        /*发送一个0信号给注册的进程,如果能发送,或者不能发送但不是返回没有进程的错误(可能权限不够),则不能再次注册通知*/

        /*有效进程*/
        if (kill(pid, 0) != -1 || errno != ESRCH) {

            if (notification == 0) {
                if (pid != getpid()) {
                    errno = EPERM;
                    flag = -1;
                }
                else {
                    mqdes->mqi_hdr->mqh_pid = 0;
                    flag = 0;
                }
            }
            else {
                errno = EBUSY;
                flag = -1;
            }
            goto __return;
        }
        /*无效进程*/
    }
    /*未设置*/
    if (notification != 0) {
        mqdes->mqi_hdr->mqh_pid = getpid();
        old = &mqdes->mqi_hdr->mqh_sigevent;
        bcopy(notification, old, sizeof(sigevent_t));
    }

    flag = 0;

__return:
    pthread_mutex_unlock(&mqdes->mqi_hdr->mqh_mutex);

    return flag;
}

void    mq_info_test(mqd_t mqdes){
    size_t i,msgsize,index;
    mq_msg *msg;
    mq_attr *mattr;
    assert(mqdes);

    mattr = &mqdes->mqi_hdr->mqh_attr;
    msgsize = sizeof(mq_msg) + ALIGN_VAL(mattr->mq_msgsize, sizeof(long));
    index = mqdes->mqi_hdr->mqh_free;
    err_msg("mq_hdr.mqh_free:%ld bytesn"
            "msghdr size:%u bytes"
            "map file size:%u bytes"
            , index
            , msgsize
            , mattr->mq_maxmsg * msgsize + index);
    err_msg("next msg offset and msg length:");
    msg = (mq_msg*)&((char*)mqdes->mqi_hdr)[index];
    for (i = 0; i < mattr->mq_maxmsg; i++) {
        fprintf(stderr, "[%ld,%ld];", msg->msg_next, msg->msg_len);
        if ((i+1)%5 == 0) {
            fprintf(stderr,"n");
        }
        msg ++ ;
    }
    if ((i+1)%5 != 0) {
        fprintf(stderr,"n");
    }

    return;
}


    
 
 

您可能感兴趣的文章:

  • 单个消息队列能实现进程间聊天功能吗?
  • 用JAVA怎样去实现队列,较好?
  • PHP双向队列实现代码
  • uclinux-2.4怎么实现如2.6的工作队列?
  • linux多线程怎么实现等待队列
  • 解析如何用两个栈来实现队列的方法
  • 如何在windows 平台上实现消息队列(多线程环境) iis7站长之家
  • C语言循环队列的表示与实现实例详解
  • 解析C++无锁队列的实现代码
  • C语言单链队列的表示与实现实例详解
  • 先进先出的队列怎么实现??
  • jquery队列queue与原生模仿其实现方法分享
  • mysql 队列 实现并发读
  • C++中用两个标准容器stack,实现一个队列的方法详解
  • 队列的动态链式存储实现代码分享
  • 用C++实现队列的程序代码
  • java使用数组和链表实现队列示例
  • 如何在windows 平台上实现消息队列(多线程环境)
  • 用JAVA怎么实现链表、队列等动态数据结构?
  • [急切求助]使用SYS V消息队列实现进程间通讯问题!!!
  • 基于DIV+ul+li实现的表格(多示例)
  • python实现绘制树枝简单示例
  • c语言实现MD5算法完整代码示例
  • ThinkPHP实现事务回滚示例代码
  • 使用libpcap实现抓包程序的步骤及代码示例
  • 修改.htaccess实现301域名重定向示例分享
  • c++实现MD5算法代码示例
  • php实现数组筛选奇数和偶数示例
  • java Servlet实现Session创建存取以及url重写代码示例
  • python实现倒计时的示例
  • 数据结构:图(有向图,无向图),在Python中的表示和实现代码示例
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 用java,怎样实现从一个类的发一个消息(消息本身也是一个类)到另一个类?
  • 类似与csdn上的短消息功能如何实现??
  • Windows下的消息时间事件机制在Unix下如何实现?
  • 用PHP实现弹出消息提示框的两种方法
  • Android消息通知栏的实现方法介绍
  • c#拦截关机注销消息的实现代码
  • DevExpress实现GridView当无数据行时提示消息
  • Windows下的消息循环机制在Unix下如何实现?
  • LINUX下SMB具体怎么实现向客户端即时发送弹出式消息?
  • MFC自定义消息的实现方法
  • java实现socket从服务器连续获取消息的示例
  • win32 api实现简单的消息窗口示例
  • asp.net 即时消息提示的实现代码
  • 使用jaxws建立webservice客户端并实现soap消息的handler验证示例
  • 微信java开发之实现微信主动推送消息
  • 基于对话框程序中让对话框捕获WM_KEYDOWN消息的实现方法
  • jQuery动态提示消息框效果的实现代码
  • PHP+memcache实现消息队列案例分享
  • C#实现微信公众号群发消息(解决一天只能发一次的限制)实例分享
  • 通过javascript实现DIV居中,兼容各浏览器版本
  • socket实现多文件并发传输,求助多线程实现问题?
  • Python GUI编程:tkinter实现一个窗口并居中代码
  • interface 到底有什么用???实现接口,怎么实现??
  • 通过javascript库JQuery实现页面跳转功能代码
  • 怎么用Jsp实现在页面实现树型结构?
  • sharepoint 2010 使用STSNavigate函数实现文件下载举例
  • windows 下的PortTunnel 在linux下怎么实现?或者相应的已经实现的软件?端口映射
  • php实现socket实现客户端和服务端数据通信源代码
  • 网站重定向用C语言实现iptables,ACL实现
  • flash AS3反射实现(describeType和getDefinitionByName)
  • 在linux下如何编程实现nslookup命令实现的IP地址和域名互相转换的功能?


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3