串口转以太客户端(增加uci、可连接多个服务器)

1、 进入barrier_breaker/package/utils文件夹,新建ttl_client

2、 该目录下的Makefile

#
# Copyright (C) 2009 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk

PKG_NAME:=ttl_client
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

define Package/ttl_client
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=serial to tcp
  DEPENDS:=+libuci +libpthread
endef

define Package/ttl_client/description
  A client of tcp to serial or serial to tcp
endef

define Build/Prepare
    mkdir -p $(PKG_BUILD_DIR)
    $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Build/Configure
endef

define Build/Compile
    $(MAKE) -C $(PKG_BUILD_DIR)         CC="$(TARGET_CC)"         CFLAGS="$(TARGET_CFLAGS) -Wall -I$(LINUX_DIR)/user_headers/include"         LDFLAGS="$(TARGET_LDFLAGS)"
endef

define Package/ttl_client/install
    $(INSTALL_DIR) $(1)/usr/sbin
    $(INSTALL_DIR) $(1)/etc/config
    $(CP) -rf ./files/ttl2tcp $(1)/etc/config/
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/ttl_client $(1)/usr/sbin/
endef

$(eval $(call BuildPackage,ttl_client))

3、 新建files文件夹,在该文件夹中新建ttl2tcp配置文件,内容如下

package ttl2tcp

config serial device
    #option name ttyUSB0
    #option name ttyS0
    option name ttyATH0
    option baudrate 115200
    option data 8
    option parity None
    option stop 1
    option enabled 1

config server
    option ipaddr 172.16.1.165
    option port 10001

config server
    option ipaddr 172.16.1.139
    option port 10001

config server
    option ipaddr 172.16.1.235
    option port 10001

4、 barrier_breaker/package/utils/ttl_client/src中的Makefile文件,内容如下

CC = gcc
CFLAGS = -Wall
OBJS = ttl_client.o

all: ttl_client

%.o: %.c
    $(CC) $(CFLAGS) -c -o [email protected] $< 

ttl_client: $(OBJS)
    $(CC) -o [email protected] $(OBJS) -luci -lpthread

clean:
    rm -f rbcfg *.o

5、 barrier_breaker/package/utils/ttl_client/src中的ttl_client.c

/*
 * ttl_client
 *
 * tingpan<[email protected]> 2015-05-31
 *
 * this is a client of serial translate to tcp or tcp translate to serial.
 * serial read overtime is 1s
 * every server read overtime is 0.5s,and the most server number is 3.
 */

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <errno.h>
#include    <sys/types.h>
#include    <sys/socket.h>
#include    <netinet/in.h>
#include     <unistd.h>
#include     <fcntl.h>
#include     <termios.h>
#include     <errno.h>
#include     <strings.h>
#include     <time.h>
#include     <arpa/inet.h>
#include     <pthread.h>
#include     <uci.h>
#include    <semaphore.h>

#define SER_MAXLINE 128
#define SOCK_MAXLINE 136//为了应对缓存溢出,多分配一个字节
#define SERVER_MAXNUM 3

struct argument
{
    int fd;
    int sockfd[SERVER_MAXNUM];
};
unsigned char on_max;
struct _options {
    char name[10];
    unsigned int baudrate;
    //unsigned int data;
    //unsigned int parity;
    //unsigned int stop;
    unsigned int enabled;
    struct in_addr ipaddr[SERVER_MAXNUM];
    unsigned int port[SERVER_MAXNUM];
};
struct _options opt;
//pthread_mutex_t socket_lock;       //互斥锁

//为了保证用户输入的波特率是个正确的值,所以需要这两个数组验证,对于设置波特率时候,前面要加个B
int speed_arr[] = { B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300,
    B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300, };  

int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300,
    115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300, };  

/*-----------------------------------------------------------------------------
  函数名:      set_speed
  参数:        int fd ,int speed
  返回值:      void
  描述:        设置fd表述符的串口波特率
 *-----------------------------------------------------------------------------*/
void set_speed(int fd ,int speed)
{
    struct termios opt;
    int i;
    int status;  

    tcgetattr(fd,&opt);
    for(i = 0;i < sizeof(speed_arr)/sizeof(int);i++)
    {
        if(speed == name_arr[i])                        //找到标准的波特率与用户一致
        {
            tcflush(fd,TCIOFLUSH);                      //清除IO输入和输出缓存
            cfsetispeed(&opt,speed_arr[i]);         //设置串口输入波特率
            cfsetospeed(&opt,speed_arr[i]);         //设置串口输出波特率   

            status = tcsetattr(fd,TCSANOW,&opt);    //将属性设置到opt的数据结构中,并且立即生效
            if(status != 0)
                perror("tcsetattr fd:");                //设置失败
            return ;
        }
        tcflush(fd,TCIOFLUSH);                          //每次清除IO缓存
    }
}
/*-----------------------------------------------------------------------------
  函数名:      set_parity
  参数:        int fd
  返回值:      int
  描述:        设置fd表述符的奇偶校验
 *-----------------------------------------------------------------------------*/
int set_parity(int fd)
{
    struct termios opt;  

    if(tcgetattr(fd,&opt) != 0)                 //或许原先的配置信息
    {
        perror("Get opt in parity error:");
        return -1;
    }  

    /*通过设置opt数据结构,来配置相关功能,以下为八个数据位,不使能奇偶校验*/
    opt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
                | INLCR | IGNCR | ICRNL | IXON);
    opt.c_oflag &= ~OPOST;
    opt.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    opt.c_cflag &= ~(CSIZE | PARENB);
    opt.c_cflag |= CS8;  

    tcflush(fd,TCIFLUSH);                           //清空输入缓存   

    if(tcsetattr(fd,TCSANOW,&opt) != 0)
    {
        perror("set attr parity error:");
        return -1;
    }  

    return 0;
}
/*-----------------------------------------------------------------------------
  函数名:      serial_init
  参数:        char *dev_path,int speed,int is_block
  返回值:      初始化成功返回打开的文件描述符
  描述:        串口初始化,根据串口文件路径名,串口的速度,和串口是否阻塞,block为1表示阻塞
 *-----------------------------------------------------------------------------*/
int serial_init(char *dev_path,int speed,int is_block)
{
    int fd;
    int flag;  

    flag = 0;
    flag |= O_RDWR;                     //设置为可读写的串口属性文件
    if(is_block == 0)
        flag |=O_NONBLOCK;              //若为0则表示以非阻塞方式打开   

    fd = open(dev_path,flag);               //打开设备文件
    if(fd < 0)
    {
        perror("Open device file err:");
        close(fd);
        return -1;
    }  

    /*打开设备文件后,下面开始设置波特率*/
    set_speed(fd,speed);                //考虑到波特率可能被单独设置,所以独立成函数   

    /*设置奇偶校验*/
    if(set_parity(fd) != 0)
    {
        perror("set parity error:");
        close(fd);                      //一定要关闭文件,否则文件一直为打开状态
        return -1;
    }  

    return fd;
}
/*-----------------------------------------------------------------------------
  函数名:      serial_send
  参数:        int fd,char *str,unsigned int len
  返回值:      发送成功返回发送长度,否则返回小于0的值
  描述:        向fd描述符的串口发送数据,长度为len,内容为str
 *-----------------------------------------------------------------------------*/
int serial_send(int fd,char *str,unsigned int len)
{
    int ret;    

    if(len > strlen(str))                    //判断长度是否超过str的最大长度
        len = strlen(str);  

    ret = write(fd,str,len);
    if(ret < 0)
    {
        perror("serial send err:");
        return -1;
    } 

    return ret;
}  

/*-----------------------------------------------------------------------------
  函数名:      serial_read
  参数:        int fd,char *str,unsigned int len,unsigned int timeout
  返回值:      在规定的时间内读取数据,超时则退出,超时时间为ms级别
  描述:        向fd描述符的串口接收数据,长度为len,存入str,timeout 为超时时间
 *-----------------------------------------------------------------------------*/
int serial_read(int fd, char *str, unsigned int len, unsigned int timeout)
{
    fd_set rfds;
    struct timeval tv;
    int ret;                                //每次读的结果
    int sret;                               //select监控结果
    int readlen = 0;                        //实际读到的字节数
    char * ptr;  

    ptr = str;                          //读指针,每次移动,因为实际读出的长度和传入参数可能存在差异   

    FD_ZERO(&rfds);                     //清除文件描述符集合
    FD_SET(fd,&rfds);                   //将fd加入fds文件描述符,以待下面用select方法监听   

    /*传入的timeout是ms级别的单位,这里需要转换为struct timeval 结构的*/
    tv.tv_sec  = timeout / 1000;
    tv.tv_usec = (timeout%1000)*1000;  

    /*防止读数据长度超过缓冲区*/
    //if(sizeof(&str) < len)
    //  len = sizeof(str);   

    /*开始读*/
    while(readlen < len)
    {
        sret = select(fd+1,&rfds,NULL,NULL,&tv);        //检测串口是否可读   

        if(sret == -1)                              //检测失败
        {
            perror("select:");
            break;
        }
        else if(sret > 0)                        //<SPAN style="WHITE-SPACE: pre"> </SPAN>//检测成功可读
        {
            ret = read(fd,ptr,1); //第三个参数为请求读取的字节数
            if(ret < 0)
            {
                perror("read err:");
                break;
            }
            else if(ret == 0)
                break;  

            readlen += ret;                             //更新读的长度
            ptr     += ret;                             //更新读的位置
        }
        else                                          //超时   sret == 0 ,没填满buf也退出循环
        {
            printf("timeout!\n");
            break;
        }
    }  

    return readlen;
}  

/**
 * socket_read: 读取tcp数据
 * @fd: socket文件描述符
 * @str:将读到的数据存放在该地址
 * @len:申请读取的字符长度
 * @timeout:超时时间,单位ms
 */
int socket_read(int fd, char *str, unsigned int len, unsigned int timeout)
{
    fd_set fdsr;
    struct timeval tv;
    int readlen = 0;
    char * ptr;
    int ret;
    ptr = str;
    // initialize file descriptor set
    FD_ZERO(&fdsr);//每次循环都要清空
    FD_SET(fd, &fdsr);
    tv.tv_sec  = timeout / 1000;
    tv.tv_usec = (timeout%1000)*1000;
    while(readlen < len){
        ret = select(fd + 1, &fdsr, NULL, NULL, &tv);
        if (ret < 0) {
            perror("select");
            //break;
            exit(-1);
        } else if (ret == 0) {
            printf("timeout\n");
            break;
          }
        //每次申请读取8个字节,但事实上是按发送端每次发送的字符串长度来确定的,如果长度小于8,则每次读取实际长度,如果大于8,则读取8字节。
        //recv多少就从缓冲区中删除多少,剩下的数据可以在下次recv时得到
        //即使子线程挂起,也一直有数据可以读,数据不丢失,真正的接收数据是协议来完成的,存放在s的接收缓冲中。
        ret = recv(fd, ptr, 8, 0);//申请8个字节
        if (ret <= 0) {//如果连接已中止,返回0。如果发生错误,返回-1
            printf("client close\n");
            close(fd);
            FD_CLR(fd, &fdsr);
            fd = 0;
        } else {
           readlen +=ret;
           ptr += ret;
           //printf("the ret length is:%d\n",readlen);
        }
    }
    return readlen;
}

/**
 * read_config: 读取配置文件
 * @popt: 配置信息保存的结构体
 */
static int read_config(struct _options *popt)
{
    static struct uci_context *ctx;
    struct uci_ptr ptr;
    char a[32];
    char i;
    unsigned char server_num = 0;

    ctx = uci_alloc_context();    

    //读取设备名称
    //if ((strcpy(a, "ttl2tcp.device.name") == NULL)
    if ((strncpy(a, "ttl2tcp.device.name", sizeof(a)) == NULL)
    //if (!snprintf(a,sizeof(a),"ttl2tcp.%s.baudrate",SERNAME)
        || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
        printf("Read ttl2tcp.device.name failed! exit.\n");
        exit(-1);
    }
    if (ptr.o) {
        strncpy(popt->name, ptr.o->v.string, sizeof(popt->name));
    } else {
        printf("ttl2tcp.device.name Not found!\n");
    }

    //读取串口波特率
    if ((strncpy(a, "ttl2tcp.device.baudrate", sizeof(a)) == NULL)
    //if (!snprintf(a,sizeof(a),"ttl2tcp.%s.baudrate",SERNAME)
        || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
        printf("Read tttl2tcp.device.baudrate failed! exit.\n");
        exit(-1);
    }
    if (ptr.o) {
        popt->baudrate = strtol(ptr.o->v.string, NULL, 10);
    } else {
        printf("ttl2tcp.device.baudrate Not found!\n");
    }

    //是否使能
    //if (!snprintf(a,sizeof(a),"ttl2tcp.%s.enabled",SERNAME)
    if ((strncpy(a, "ttl2tcp.device.enabled", sizeof(a)) == NULL)
        || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
        printf("Read ttl2tcp.device.enabled failed! exit.\n");
        exit(-1);
    }
    if (ptr.o) {
        popt->enabled = strtol(ptr.o->v.string, NULL, 10);
    } else {
        printf("ttl2tcp.device.enabled Not found!\n");
    }

    for(i=0; i<SERVER_MAXNUM; i++){
        //读取ip地址
        //if ((strncpy(a, "[email protected][0].ipaddr",sizeof(a)) == NULL)
        if (!snprintf(a,sizeof(a),"[email protected][%d].ipaddr",i)
            || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
            printf("Read [email protected][%d].ipaddr failed! exit.\n",i);
            exit(-1);
        }
        if (ptr.o) {
            unsigned int laddr;
            laddr = inet_addr(ptr.o->v.string);//因为ipaddr为网络字节顺序,大端字节序,而输入的为主机字节序
            memcpy(&popt->ipaddr[i], &laddr, 4);
        } else {
            printf("[email protected][%d].ipaddr Not found!\n",i);
        }
        //读取port
        //if ((strcpy(a, "[email protected][0].port") == NULL)
        if (!snprintf(a,sizeof(a),"[email protected][%d].port",i)
            || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
            printf("Read [email protected][%d].port failed! exit.\n",i);
            exit(-1);
        }
        if (ptr.o) {
            popt->port[i] = strtol(ptr.o->v.string, NULL, 10);
            server_num++;
        } else {
            printf("[email protected][%d].port Not found!\n",i);
        }
    }
    uci_free_context(ctx);
    return server_num;
}

/**
 * conn_nonb: 非阻塞connect
 * @sockfd: socket文件描述符
 * @saptr:指向数据结构sockaddr的指针,其中包括目的端口和IP地址
 * @salen:sockaddr的长度
 * @nsec:超时时间,单位ms
 */
int conn_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec)
{
    int flags, n, error, code;
    socklen_t len;
    fd_set wset;
    struct timeval tval;

    flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    error = 0;
    if ((n = connect(sockfd, saptr, salen)) == 0) {    //马上连接成功,可能性小
        printf("conn_nonb success!\n");
        goto done;
    }else if (n < 0 && errno != EINPROGRESS){    //多次连接或服务端没开启,出错 ,第一次一般执行不到该处。
        printf("conn_nonb error!\n");
        return (-1);
    }

    /* Do whatever we want while the connect is taking place */
    //连接建立已经启动,但是尚未完成
    FD_ZERO(&wset);
    FD_SET(sockfd, &wset);
    tval.tv_sec = nsec;
    tval.tv_usec = 0;
    //printf("conn_nonb select start!\n");
    if ((n = select(sockfd+1, NULL, &wset, //有连接要处理
                    NULL, nsec ? &tval : NULL)) == 0) {
        close(sockfd);  /* timeout */
        errno = ETIMEDOUT;
        printf("conn_nonb select timeout!\n");
        return (-1);
    }

    if (FD_ISSET(sockfd, &wset)) {
        len = sizeof(error);
        code = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
        /* 如果发生错误,Solaris实现的getsockopt返回-1,
         * 把pending error设置给errno. Berkeley实现的
         * getsockopt返回0, pending error返回给error.
         * 我们需要处理这两种情况 */
        if (code < 0 || error) {
            close(sockfd);
            if (error)
                errno = error;
            printf("conn_nonb getsockopt error!\n");
            return (-1);
        }
    } else {
        fprintf(stderr, "select error: sockfd not set");
        exit(0);
    }

done:
    fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */
    return (0);
}

void *socket_thread(void *arg)
{
    char sockbuf[SOCK_MAXLINE];
    int sreadlen = 0;
    int freadlen = 0;
    unsigned char i;
    struct argument thread_arg;
    thread_arg = *(struct argument *)arg;
    memset(sockbuf, 0, sizeof(sockbuf));
    while(1)
    {
        for    (i=0; i<on_max;i++)
        {
            //pthread_mutex_lock(&socket_lock);//lock
            sreadlen = socket_read(thread_arg.sockfd[i], sockbuf, SOCK_MAXLINE-8, 500);//为了防止缓存溢出,少读取一个字节
            printf("the sockbuf is:%s\n", sockbuf);//打印出数据
            printf("the sockbuf length is:%d\n",sreadlen);
            freadlen = serial_send(thread_arg.fd,sockbuf,sreadlen);
            printf("send %d bytes!\n",freadlen);
            memset(sockbuf, 0, sizeof(sockbuf));
            //pthread_mutex_unlock(&socket_lock);//unlock
            usleep(1);
        }
    }
}

int main(int argc, char** argv)
{
    //串口变量定义
    int fd;
    char str[]="hello linux serial!"; //字符串初始化
    char serbuf[SER_MAXLINE];
    int readlen;
    char dev_path[20];

    // socket变量定义
    int sockfd[SERVER_MAXNUM];//SERVER_MAXNUM
    struct sockaddr_in servaddr[SERVER_MAXNUM];//SERVER_MAXNUM
    unsigned char i;
    unsigned char on_sockfd[SERVER_MAXNUM] = {0};
    on_max = 0;//最大上线个数

    //多线程
    pthread_t thread;
    int mret;
    struct argument arg;

    //读取配置文件
    unsigned char server_num;//服务器个数初始化
    server_num = read_config(&opt);
    if (opt.enabled != 1)
    {
        printf("do not enable ttl_client!\n");
        exit(-1);
    }

    //串口初始化
    if (!snprintf(dev_path,sizeof(dev_path),"/dev/%s",opt.name)
        || (fd = serial_init(dev_path,opt.baudrate,1)) < 0)
    {
        perror("serial init err:");
        return -1;
    }
    memset(serbuf, 0, sizeof(serbuf));

    //socket始化
    for (i=0; i<server_num; i++)
    {
        printf("socket init %d/%d\n",i,server_num);
        if( (sockfd[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            printf("create socket2 error: %s(errno: %d)\n", strerror(errno),errno);
            exit(0);
        }
        memset(&servaddr[i], 0, sizeof(servaddr[i]));
        servaddr[i].sin_family = AF_INET;
        servaddr[i].sin_port = htons(opt.port[i]);
        servaddr[i].sin_addr = opt.ipaddr[i];//与配置文件有关,注意配置文件要正确

        //if( connect(sockfd[i], (struct sockaddr*)&servaddr[i], sizeof(servaddr[i])) < 0)
        //非阻塞连接10s,如果前一个sockfd没有connect成功,则下次将建立一样的文件描述符号
        if( conn_nonb(sockfd[i], (struct sockaddr*)&servaddr[i], sizeof(servaddr[i]),10) < 0)
        {
            printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
            continue;
            //exit(0);
        }
        on_sockfd[on_max++] = i;
        printf("send msg to server[%d]: %d\n",i,on_max-1);//on_max-1为上线客户端的新编号
        //socket发送
        if( send(sockfd[i], str, strlen(str), 0) < 0)
        {
            printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
            exit(0);
        }
    }
    //如果没有一个服务器上线
    if (on_max == 0)
    {
        exit(0);
    }

    //锁
    //pthread_mutex_init(&socket_lock, NULL);

    //创建多线程
    arg.fd=fd;
    for    (i=0; i<on_max;i++)
    {
        arg.sockfd[i]=sockfd[on_sockfd[i]];
    }
    mret = pthread_create(&thread, NULL, socket_thread, (void *)(long)&arg);
    if (mret != 0)
    {
        printf("Create thread failed\n");
        exit(mret);
    }
    printf("Create thread\n"); 

    //串口转tcp
    while(1)
    {
        readlen = serial_read(fd,serbuf,SER_MAXLINE,1000);//1s内如果数据没有装满buf,则读取完毕。 如果数据量大,则读取的速度也越快。
        printf("the serbuf is :%s\n",serbuf);
        printf("the serbuf length is :%d\n",readlen);
        for    (i=0; i<on_max;i++)
        {
            printf("sockfd[%d]:%d\n",i,sockfd[on_sockfd[i]]);
            if( send(sockfd[on_sockfd[i]], serbuf, readlen, 0) < 0)//serbuf中有数据可以发送才会执行这条语句
            {
                printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);//服务端断掉,则发送失败。
                exit(0);
            }
        }
        memset(serbuf, 0, sizeof(serbuf));
        sleep(1);
    }
    //退出
    close(fd);
    for    (i=0; i<server_num;i++)
    close(sockfd[i]);
    exit(0);
}
时间: 2024-10-11 02:48:27

串口转以太客户端(增加uci、可连接多个服务器)的相关文章

HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)

HTTP实现长连接 HTTP是无状态的 也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.如果客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源,如JavaScript文件.图像文件.CSS文件等:当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话 HTTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持(貌似最新的 http1.0 可以显示的指定 keep-alive),但还是无状态的,或者说是不可以信任的.

免安装Oracle客户端使用PL/SQL连接Oracle的2种方法

作者:netshuai  来源:博客园  发布时间:2009-10-23 09:19  阅读:171 次  原文链接   [收藏] 方法一: 大家都知道,用PL/SQL连接Oracle,是需要安装Oracle客户端软件的.有没要想过不安装Oracle客户端直接连接Oracle呢? 其实我一直想这样做,因为这个客户端实在太让人讨厌了!!!不但会安装一个JDK,而且还会把自己放在环境变量的最前面,会造成不小的麻烦. 其实我之前问过很多人的,但是他们都说一定需要安装Oracle客户端的.......直

支持并发的http客户端(基于tcp连接池以及netty)

闲来无事,将以前自己写的一个库放出来吧.. 有的时候会有这样子的需求: (1)服务器A通过HTTP协议来访问服务器B (2)服务器A可能会并发的像B发送很多HTTP请求 类似于上述的需求,可能并不常见...因为在业务中确实遇到了这样子的场景,所以就自己动手开发了一个库... 实现原理: (1)底层IO通过netty搞 (2)维护一个tcp的长连接池,这样子就不用每次发送请求还要建立一个tcp连接了... 下面直接来看怎么用吧: (1)最常规的用法,向www.baidu.com发送100次get请

VPN客户端出现“无法完成连接尝试”的解决方法

VPN客户端出现“无法完成连接尝试”的解决方法 在Windows 7.Windows 8.Windows 10的客户端,在连接VPN服务器的时候,如果出现“无法完成连接尝试”,如图1-1所示. 图1-1 无法完成连接尝试 在图1-1中单击“详细信息”,此时会提示“服务器 XXX具有 YYY颁发的有效证书,但YYY未配置为该配置文件的有效信任密钥.而且,服务器XXX未配置为有效的NPS服务器,无法连接到该配置文件”,如图1-2所示.单击“连接”按钮,才能连接到VPN服务器. 图1-2 无法连接到配

局域网内客户端无法使用机器名连接SQLServer服务器

在生产环境中有时会要求使用机器名连接SQLServer服务器,但有时捣好久都没法连上~ 针对这个问题做个简短记录,防止以后自己再遇到记不起原因,也方便一下其他同行! 废话不多说,作为工作多年的老家伙了,以下工作肯定确保过的: SQL Server服务器端的[命名管道]协议是开启了的! SQL Server服务器端的网卡NetBIOS解析功能也开启了的! SQL Server服务器端使用着的经典的1433端口在防火墙上开了例外的! 已经确保在客户端使用IP能连接上SQL Server服务器的! 放

通过使用精简客户端,且不需要安装的客户端,配合PLSQL连接oracle数据库

通过使用精简客户端,且不需要安装的客户端,配合PLSQL连接oracle数据库. 首先下载安装包在Oralce官方网站上下载Oracle Instantclient Basic package.地址如下:http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html在这个页面的中部找到Instant Client,在Instant Client Downloads中选择合适的版本下载. 第二

Java NIO SocketChannel客户端例子(支持连接失败后自动重连)

这两天想找找标题里说的这个示例代码,发现网上这么多教程,连怎么样实现自动重连都不讲,所以把自己写的例子贴上来.仅仅使用递归,不使用多线程,就可以实现初步的目的: import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; impor

如何使用VNC Viewer连接远程CentOS服务器

如何使用VNC Viewer连接远程CentOS服务器 安装图形界面 1. yum groupinstall  -y  "Desktop"   yum groupinstall -y "X Window System" 2.vi /etc/inittab 3. 4.Reboot Linux VNC server的安装及简单配置使用 1,打开终端使用yum命令安装vnc sever.命令:yum install tigervnc-server -y 2,将vncser

WCF下载***$metadata”时出错。 无法连接到远程服务器由于目标计算机积极拒绝,无法连接。元数据包含无法解析的引用http://localhost 没有终结点在侦听可以接受消这通常是由于不正

错误描述:新建的WCF类库项目,由WinForm程序托管,托管的时候没有错误,但是在客户端引用服务的时候,却找不到服务,而且 如果打开多个服务也不会报端口占用错误. 解决思路:开始以为是配置文件的问题,就开始从配置文件上下手,无果.然后又检查防火墙,重启电脑,都不行.后来在不托管服务的情况下 引用服务,提示一样的错误, 打开监听端口一看,没有我定义的8009端口,果然是托管没有成功,否则端口肯定是在监听状态. 解决办法:去掉using,因为当Form1_Load执行完成后,host也会被usin