C++ socket端口复用的问题

环境
公网服务器1台,内网服务器若干。其中一台内网可以和公网连接通信,打算在公网上用socket做端口转发来实现访各台问内网的目的。功能已经实现了(一对一连接),但端口复用问题一直很困惑,请各位帮忙检查一下代码,谢谢

公网代码

// 绑定两个服务器socket
void bind2bind(int port1, int port2)
{
    char msgbuf[100];
    memset(msgbuf, 0, 100);
    sprintf(msgbuf, "[+] 服务器初始化...\r\n");
    outprint(msgbuf, strlen(msgbuf));
    int fd0, fd1, fd2;
    if ((fd0 = create_socket()) == 0) return;
    if ((fd1 = create_socket()) == 0) return;
    if ((fd2 = create_socket()) == 0) return;

    int port0 = 5501;
    if (create_server(fd0, port0) == 0)
    {
        closesocket(fd0);
        return;
    }
    sprintf(msgbuf, "[+] 成功监听通信端口: %d\r\n", port0);
    outprint(msgbuf, strlen(msgbuf));

    // 创建第一个服务器
    if (create_server(fd1, port1) == 0)
    {
        closesocket(fd1);
        return;
    }
    sprintf(msgbuf, "[+] 成功监听隧道端口: %d\r\n", port1);
    outprint(msgbuf, strlen(msgbuf));

    // 创建第二个服务器
    if (create_server(fd2, port2) == 0)
    {
        closesocket(fd2);
        return;
    }
    sprintf(msgbuf, "[+] 成功监听上线端口: %d\r\n", port2);
    outprint(msgbuf, strlen(msgbuf));

    // 等待两端上线
    while (1)
    {
        sprintf(msgbuf, "[%d] 正在建立通信端口: %d\r\n", idx, port0);
        outprint(msgbuf, strlen(msgbuf));
        struct sockaddr_in client0;
        int size0 = sizeof(struct sockaddr);
        int sockfd0 = accept(fd0, (struct sockaddr *)&client0, &size0);
        sprintf(msgbuf, "[%d] 通信端口连接成功 IP地址: %s\r\n", idx, inet_ntoa(client0.sin_addr));
        outprint(msgbuf, strlen(msgbuf));

        sprintf(msgbuf, "[%d] 发送idx值: %d\r\n", idx, idx);
        outprint(msgbuf, strlen(msgbuf));
        char idxbuf[10];
        memset(idxbuf, 0, 10);
        sprintf(idxbuf, "%d", idx);
        int send0 = send(sockfd0, idxbuf, strlen(idxbuf)+1, 0);
        if (send0 <= 0)
        {
            closesocket(sockfd0);
            continue;
        }
        closesocket(sockfd0);

        sprintf(msgbuf, "[%d] 正在建立隧道端口: %d\r\n", idx, port1);
        outprint(msgbuf, strlen(msgbuf));
        struct sockaddr_in client1;
        int size1 = sizeof(struct sockaddr);
        int sockfd1 = accept(fd1, (struct sockaddr *)&client1, &size1);

        sprintf(msgbuf, "[%d] 正在建立上线端口: %d\r\n", idx, port2);
        outprint(msgbuf, strlen(msgbuf));
        struct sockaddr_in client2;
        int size2 = sizeof(struct sockaddr);
        int sockfd2 = accept(fd2, (struct sockaddr *)&client2, &size2);
        sprintf(msgbuf, "[%d] 通过上线端口连接成功 IP地址: %s\r\n", idx, inet_ntoa(client2.sin_addr));
        outprint(msgbuf, strlen(msgbuf));

        // socket
        transocket sock;
        sock.fd1 = sockfd1;
        sock.fd2 = sockfd2;
        sock.idx = idx;
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)transmitdata, (LPVOID)&sock, 0, NULL);
        idx++;
    }
}
负责通信的内网代码
{
        int port0 = 5501;
        char msgbuf[100];
        memset(msgbuf, 0, 100);
        while (1)
        {
            int sockfd0;
            if ((sockfd0 = create_socket()) == 0) return 0;

            // 通过5501端口连接服务器
            sprintf(msgbuf, "[+] 正在连接服务器 %s:%d\r\n", sConnectHost, port0);
            outprint(msgbuf, strlen(msgbuf));
            if (client_connect(sockfd0, sConnectHost, port0) == 0)
            {
                closesocket(sockfd0);
                continue;
            }
            sprintf(msgbuf, "[+] 服务器连接成功\r\n");
            outprint(msgbuf, strlen(msgbuf));

            // 接收服务器idx值
            char idxbuf[10];
            memset(idxbuf, 0, 10);
            int read0 = recv(sockfd0, idxbuf, 10, 0);
            if (read0 > 0)
            {
                // 在线程内执行conn2conn
                int nIdx = atoi(idxbuf);
                tranconn2conn conn;
                conn.host1 = sConnectHost;
                conn.port1 = iConnectPort;
                conn.host2 = sTransmitHost;
                conn.port2 = iTransmitPort;
                conn.idx = nIdx;
                CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)conn2conn, (LPVOID)&conn, 0, NULL);
            }
        }
        closeallfd();
}

// 内网转发数据
void conn2conn(LPVOID data)
{
    tranconn2conn *conn = (tranconn2conn *)data;

    char msgbuf[100];
    memset(msgbuf, 0, 100);
    while (1)
    {
        int sockfd1, sockfd2;
        if ((sockfd1 = create_socket()) == 0) return;
        if ((sockfd2 = create_socket()) == 0) return;

        sprintf(msgbuf, "[%d] 正在连接服务器 %s:%d\r\n", conn->idx, conn->host1, conn->port1);
        outprint(msgbuf, strlen(msgbuf));
        if (client_connect(sockfd1, conn->host1, conn->port1) == 0)
        {
            closesocket(sockfd1);
            closesocket(sockfd2);
            continue;
        }
        sprintf(msgbuf, "[%d] 服务器连接成功\r\n", conn->idx);
        outprint(msgbuf, strlen(msgbuf));

        sprintf(msgbuf, "[%d] 正在连接内网 %s:%d\r\n", conn->idx, conn->host2, conn->port2);
        outprint(msgbuf, strlen(msgbuf));
        if (client_connect(sockfd2, conn->host2, conn->port2) == 0)
        {
            closesocket(sockfd1);
            closesocket(sockfd2);
            continue;
        }
        sprintf(msgbuf, "[%d] 内网连接成功\r\n", conn->idx);
        outprint(msgbuf, strlen(msgbuf));

        // socket
        transocket sock;
        sock.fd1 = sockfd1;
        sock.fd2 = sockfd2;
        sock.idx = conn->idx;
        transmitdata(&sock);
    }
}
数据转发代码
// 服务器转发数据
void transmitdata(LPVOID data)
{
    transocket *sock = (transocket *)data;

    // 准备采用select模型
    fd_set readfd, writefd;
    char read_in1[MAXSIZE], send_out1[MAXSIZE];
    char read_in2[MAXSIZE], send_out2[MAXSIZE];

    struct sockaddr_in client1, client2;
    char host1[20], host2[20], msgbuf[100];
    memset(host1, 0, 20);
    memset(host2, 0, 20);
    memset(msgbuf, 0, 100);

    int port1 = 0, port2 = 0;
    int structsize1 = sizeof(struct sockaddr);
    int structsize2 = sizeof(struct sockaddr);

    // 获取第一客户端信息
    if (getpeername(sock->fd1, (struct sockaddr *)&client1, &structsize1) < 0)
    {
        strcpy(host1, "fd1");
    }
    else
    {
        strcpy(host1, inet_ntoa(client1.sin_addr));
        port1 = ntohs(client1.sin_port);
    }

    // 获取第二客户端信息
    if (getpeername(sock->fd2, (struct sockaddr *)&client2, &structsize2) < 0)
    {
        strcpy(host2, "fd2");
    }
    else
    {
        strcpy(host2, inet_ntoa(client2.sin_addr));
        port2 = ntohs(client2.sin_port);
    }

    sprintf(msgbuf, "[%d] fd1: %d, fd2: %d\r\n", sock->idx, sock->fd1, sock->fd2);
    outprint(msgbuf, strlen(msgbuf));

    // 输出两个客户端信息
    sprintf(msgbuf, "[%d] 建立数据转发走向(%s:%d <-> %s:%d)\r\n", sock->idx, host1, port1, host2, port2);
    outprint(msgbuf, strlen(msgbuf));

    // 最大检测数目
    int maxfd = max(sock->fd1, sock->fd2) + 1;

    // 设置检测超时
    struct timeval timeset;
    timeset.tv_sec = TIMEOUT;           // 超时秒数
    timeset.tv_usec = 0;                // 超时微秒

    // 位模式清零
    memset(send_out1, 0, MAXSIZE);
    memset(send_out2, 0, MAXSIZE);

    // 可读长度
    int totalread1 = 0, totalread2 = 0;
    while (1)
    {
        // 采用select异步模型
        FD_ZERO(&readfd);
        FD_ZERO(&writefd);

        // 添加到fd集合
        FD_SET(sock->fd1, &readfd);
        FD_SET(sock->fd1, &writefd);
        FD_SET(sock->fd2, &readfd);
        FD_SET(sock->fd2, &writefd);

        // 第一个参数会被系统忽略掉
        int result = select(maxfd, &readfd, &writefd, NULL, &timeset);
        if ((result < 0) && (errno != EINTR))
        {
            // 程序出错
            sprintf(msgbuf, "[%d] Error: select函数出错\r\n", sock->idx);
            outprint(msgbuf, strlen(msgbuf));
            break;
        }
        else if (result == 0)
        {
            // 等待超时
            sprintf(msgbuf, "[%d] Error: select函数等待超时\r\n", sock->idx);
            outprint(msgbuf, strlen(msgbuf));
            continue;
        }

        // fd1可读, 只要可读, 一次即可读取完整, 无需while循环
        if (FD_ISSET(sock->fd1, &readfd) && totalread1 < MAXSIZE)
        {
            int read1 = recv(sock->fd1, read_in1, MAXSIZE - totalread1, 0);
            if (read1 == 0 || (read1 < 0 && errno != EINTR))
            {
                sprintf(msgbuf, "[%d] Error: 读取fd1出错\r\n", sock->idx);
                outprint(msgbuf, strlen(msgbuf));
                break;
            }

            // 改变fd1的发送缓冲区和他的大小(接了就要发嘛)
            memcpy(send_out1 + totalread1, read_in1, read1);
            sprintf(msgbuf, "[%d] fd1成功在地址: %16s:%d上面读取%d字节\r\n", sock->idx, host1, port1, read1);
            outprint(msgbuf, strlen(msgbuf));
            totalread1 += read1;
            memset(read_in1, 0, MAXSIZE);
        }

        // fd2可写
        if (FD_ISSET(sock->fd2, &writefd))
        {
            int err = 0;
            int sendcount1 = 0;

            // 发送的话可能一次发不完(数据包过大)
            while (totalread1 > 0)
            {
                int send1 = send(sock->fd2, send_out1+sendcount1, totalread1, 0);
                if (send1 == 0 || (send1 < 0 && errno != EINTR))
                {
                    sprintf(msgbuf, "[%d] Error: 写入fd2出错\r\n", sock->idx);
                    outprint(msgbuf, strlen(msgbuf));
                    err = 1;
                    break;
                }
                if ((send1 < 0) && (errno == ENOSPC)) break;

                // 改变缓冲区大小
                sendcount1 += send1;
                totalread1 -= send1;
                sprintf(msgbuf, "[%d] fd2成功在地址: %16s:%d上面发送%d字节\r\n", sock->idx, host2, port2, send1);
                outprint(msgbuf, strlen(msgbuf));
            }

            // 检验出错
            if (err == 1) break;

            // 如果发送了数据, 并且没有发送干净
            if ((totalread1 > 0) && (sendcount1 > 0))
            {
                // 理论上下面两行永远不会执行
                memcpy(send_out1, send_out1 + sendcount1, totalread1);
                memset(send_out1 + totalread1, 0, MAXSIZE - totalread1);
            }
            else
            {
                memset(send_out1, 0, MAXSIZE);
            }
        }

        // fd2可读, 只要可读, 一次即可读取完整, 无需while循环
        if (FD_ISSET(sock->fd2, &readfd) && totalread2 < MAXSIZE)
        {

            int read2 = recv(sock->fd2, read_in2, MAXSIZE - totalread2, 0);
            if (read2 == 0 || (read2 < 0 && errno != EINTR))
            {
                sprintf(msgbuf, "[%d] Error: 读取fd2出错\r\n", sock->idx);
                outprint(msgbuf, strlen(msgbuf));
                break;
            }

            // 接了就立即发出去
            memcpy(send_out2 + totalread2, read_in2, read2);
            sprintf(msgbuf, "[%d] fd2成功在地址: %16s:%d上面读取%d字节\r\n", sock->idx, host2, port2, read2);
            outprint(msgbuf, strlen(msgbuf));
            totalread2 += read2;
            memset(read_in2, 0, MAXSIZE);
        }

        // fd1可写
        if (FD_ISSET(sock->fd1, &writefd))
        {
            int err2 = 0;
            int sendcount2 = 0;
            while (totalread2 > 0)
            {
                int send2 = send(sock->fd1, send_out2 + sendcount2, totalread2, 0);
                if (send2 == 0 || (send2 < 0 && errno != EINTR))
                {
                    sprintf(msgbuf, "[%d] Error: 写入fd1出错\r\n", sock->idx);
                    outprint(msgbuf, strlen(msgbuf));
                    err2 = 1;
                    break;
                }
                if ((send2 < 0) && (errno == ENOSPC)) break;
                sendcount2 += send2;
                totalread2 -= send2;
                sprintf(msgbuf, "[%d] fd1成功在地址: %16s:%d上面发送%d字节\r\n", sock->idx, host1, port1, send2);
                outprint(msgbuf, strlen(msgbuf));
            }
            if (err2 == 1) break;
            if ((totalread2 > 0) && (sendcount2 > 0))
            {
                memcpy(send_out2, send_out2+sendcount2, totalread2);
                memset(send_out2 + totalread2, 0, MAXSIZE - totalread2);
            }
            else
            {
                memset(send_out2, 0, MAXSIZE);
            }
        }
    }

    // 关闭socket
    closesocket(sock->fd1);
    closesocket(sock->fd2);
    sprintf(msgbuf, "[%d] 成功关闭掉两个socket, fd1, fd2\r\n", sock->idx);
    outprint(msgbuf, strlen(msgbuf));
    sprintf(msgbuf, "[%d] 本次数据转发结束\r\n\n", sock->idx);
    outprint(msgbuf, strlen(msgbuf));
}

1个回答

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
C++ socket端口复用的问题
环境 公网服务器1台,内网服务器若干。其中一台内网可以和公网连接通信,打算在公网上用socket做端口转发来实现访各台问内网的目的。功能已经实现了(一对一连接),但端口复用问题一直很困惑,请各位帮忙检查一下代码,谢谢 公网代码 ``` // 绑定两个服务器socket void bind2bind(int port1, int port2) { char msgbuf[100]; memset(msgbuf, 0, 100); sprintf(msgbuf, "[+] 服务器初始化...\r\n"); outprint(msgbuf, strlen(msgbuf)); int fd0, fd1, fd2; if ((fd0 = create_socket()) == 0) return; if ((fd1 = create_socket()) == 0) return; if ((fd2 = create_socket()) == 0) return; int port0 = 5501; if (create_server(fd0, port0) == 0) { closesocket(fd0); return; } sprintf(msgbuf, "[+] 成功监听通信端口: %d\r\n", port0); outprint(msgbuf, strlen(msgbuf)); // 创建第一个服务器 if (create_server(fd1, port1) == 0) { closesocket(fd1); return; } sprintf(msgbuf, "[+] 成功监听隧道端口: %d\r\n", port1); outprint(msgbuf, strlen(msgbuf)); // 创建第二个服务器 if (create_server(fd2, port2) == 0) { closesocket(fd2); return; } sprintf(msgbuf, "[+] 成功监听上线端口: %d\r\n", port2); outprint(msgbuf, strlen(msgbuf)); // 等待两端上线 while (1) { sprintf(msgbuf, "[%d] 正在建立通信端口: %d\r\n", idx, port0); outprint(msgbuf, strlen(msgbuf)); struct sockaddr_in client0; int size0 = sizeof(struct sockaddr); int sockfd0 = accept(fd0, (struct sockaddr *)&client0, &size0); sprintf(msgbuf, "[%d] 通信端口连接成功 IP地址: %s\r\n", idx, inet_ntoa(client0.sin_addr)); outprint(msgbuf, strlen(msgbuf)); sprintf(msgbuf, "[%d] 发送idx值: %d\r\n", idx, idx); outprint(msgbuf, strlen(msgbuf)); char idxbuf[10]; memset(idxbuf, 0, 10); sprintf(idxbuf, "%d", idx); int send0 = send(sockfd0, idxbuf, strlen(idxbuf)+1, 0); if (send0 <= 0) { closesocket(sockfd0); continue; } closesocket(sockfd0); sprintf(msgbuf, "[%d] 正在建立隧道端口: %d\r\n", idx, port1); outprint(msgbuf, strlen(msgbuf)); struct sockaddr_in client1; int size1 = sizeof(struct sockaddr); int sockfd1 = accept(fd1, (struct sockaddr *)&client1, &size1); sprintf(msgbuf, "[%d] 正在建立上线端口: %d\r\n", idx, port2); outprint(msgbuf, strlen(msgbuf)); struct sockaddr_in client2; int size2 = sizeof(struct sockaddr); int sockfd2 = accept(fd2, (struct sockaddr *)&client2, &size2); sprintf(msgbuf, "[%d] 通过上线端口连接成功 IP地址: %s\r\n", idx, inet_ntoa(client2.sin_addr)); outprint(msgbuf, strlen(msgbuf)); // socket transocket sock; sock.fd1 = sockfd1; sock.fd2 = sockfd2; sock.idx = idx; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)transmitdata, (LPVOID)&sock, 0, NULL); idx++; } } ``` ``` 负责通信的内网代码 { int port0 = 5501; char msgbuf[100]; memset(msgbuf, 0, 100); while (1) { int sockfd0; if ((sockfd0 = create_socket()) == 0) return 0; // 通过5501端口连接服务器 sprintf(msgbuf, "[+] 正在连接服务器 %s:%d\r\n", sConnectHost, port0); outprint(msgbuf, strlen(msgbuf)); if (client_connect(sockfd0, sConnectHost, port0) == 0) { closesocket(sockfd0); continue; } sprintf(msgbuf, "[+] 服务器连接成功\r\n"); outprint(msgbuf, strlen(msgbuf)); // 接收服务器idx值 char idxbuf[10]; memset(idxbuf, 0, 10); int read0 = recv(sockfd0, idxbuf, 10, 0); if (read0 > 0) { // 在线程内执行conn2conn int nIdx = atoi(idxbuf); tranconn2conn conn; conn.host1 = sConnectHost; conn.port1 = iConnectPort; conn.host2 = sTransmitHost; conn.port2 = iTransmitPort; conn.idx = nIdx; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)conn2conn, (LPVOID)&conn, 0, NULL); } } closeallfd(); } // 内网转发数据 void conn2conn(LPVOID data) { tranconn2conn *conn = (tranconn2conn *)data; char msgbuf[100]; memset(msgbuf, 0, 100); while (1) { int sockfd1, sockfd2; if ((sockfd1 = create_socket()) == 0) return; if ((sockfd2 = create_socket()) == 0) return; sprintf(msgbuf, "[%d] 正在连接服务器 %s:%d\r\n", conn->idx, conn->host1, conn->port1); outprint(msgbuf, strlen(msgbuf)); if (client_connect(sockfd1, conn->host1, conn->port1) == 0) { closesocket(sockfd1); closesocket(sockfd2); continue; } sprintf(msgbuf, "[%d] 服务器连接成功\r\n", conn->idx); outprint(msgbuf, strlen(msgbuf)); sprintf(msgbuf, "[%d] 正在连接内网 %s:%d\r\n", conn->idx, conn->host2, conn->port2); outprint(msgbuf, strlen(msgbuf)); if (client_connect(sockfd2, conn->host2, conn->port2) == 0) { closesocket(sockfd1); closesocket(sockfd2); continue; } sprintf(msgbuf, "[%d] 内网连接成功\r\n", conn->idx); outprint(msgbuf, strlen(msgbuf)); // socket transocket sock; sock.fd1 = sockfd1; sock.fd2 = sockfd2; sock.idx = conn->idx; transmitdata(&sock); } } ``` ``` 数据转发代码 // 服务器转发数据 void transmitdata(LPVOID data) { transocket *sock = (transocket *)data; // 准备采用select模型 fd_set readfd, writefd; char read_in1[MAXSIZE], send_out1[MAXSIZE]; char read_in2[MAXSIZE], send_out2[MAXSIZE]; struct sockaddr_in client1, client2; char host1[20], host2[20], msgbuf[100]; memset(host1, 0, 20); memset(host2, 0, 20); memset(msgbuf, 0, 100); int port1 = 0, port2 = 0; int structsize1 = sizeof(struct sockaddr); int structsize2 = sizeof(struct sockaddr); // 获取第一客户端信息 if (getpeername(sock->fd1, (struct sockaddr *)&client1, &structsize1) < 0) { strcpy(host1, "fd1"); } else { strcpy(host1, inet_ntoa(client1.sin_addr)); port1 = ntohs(client1.sin_port); } // 获取第二客户端信息 if (getpeername(sock->fd2, (struct sockaddr *)&client2, &structsize2) < 0) { strcpy(host2, "fd2"); } else { strcpy(host2, inet_ntoa(client2.sin_addr)); port2 = ntohs(client2.sin_port); } sprintf(msgbuf, "[%d] fd1: %d, fd2: %d\r\n", sock->idx, sock->fd1, sock->fd2); outprint(msgbuf, strlen(msgbuf)); // 输出两个客户端信息 sprintf(msgbuf, "[%d] 建立数据转发走向(%s:%d <-> %s:%d)\r\n", sock->idx, host1, port1, host2, port2); outprint(msgbuf, strlen(msgbuf)); // 最大检测数目 int maxfd = max(sock->fd1, sock->fd2) + 1; // 设置检测超时 struct timeval timeset; timeset.tv_sec = TIMEOUT; // 超时秒数 timeset.tv_usec = 0; // 超时微秒 // 位模式清零 memset(send_out1, 0, MAXSIZE); memset(send_out2, 0, MAXSIZE); // 可读长度 int totalread1 = 0, totalread2 = 0; while (1) { // 采用select异步模型 FD_ZERO(&readfd); FD_ZERO(&writefd); // 添加到fd集合 FD_SET(sock->fd1, &readfd); FD_SET(sock->fd1, &writefd); FD_SET(sock->fd2, &readfd); FD_SET(sock->fd2, &writefd); // 第一个参数会被系统忽略掉 int result = select(maxfd, &readfd, &writefd, NULL, &timeset); if ((result < 0) && (errno != EINTR)) { // 程序出错 sprintf(msgbuf, "[%d] Error: select函数出错\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); break; } else if (result == 0) { // 等待超时 sprintf(msgbuf, "[%d] Error: select函数等待超时\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); continue; } // fd1可读, 只要可读, 一次即可读取完整, 无需while循环 if (FD_ISSET(sock->fd1, &readfd) && totalread1 < MAXSIZE) { int read1 = recv(sock->fd1, read_in1, MAXSIZE - totalread1, 0); if (read1 == 0 || (read1 < 0 && errno != EINTR)) { sprintf(msgbuf, "[%d] Error: 读取fd1出错\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); break; } // 改变fd1的发送缓冲区和他的大小(接了就要发嘛) memcpy(send_out1 + totalread1, read_in1, read1); sprintf(msgbuf, "[%d] fd1成功在地址: %16s:%d上面读取%d字节\r\n", sock->idx, host1, port1, read1); outprint(msgbuf, strlen(msgbuf)); totalread1 += read1; memset(read_in1, 0, MAXSIZE); } // fd2可写 if (FD_ISSET(sock->fd2, &writefd)) { int err = 0; int sendcount1 = 0; // 发送的话可能一次发不完(数据包过大) while (totalread1 > 0) { int send1 = send(sock->fd2, send_out1+sendcount1, totalread1, 0); if (send1 == 0 || (send1 < 0 && errno != EINTR)) { sprintf(msgbuf, "[%d] Error: 写入fd2出错\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); err = 1; break; } if ((send1 < 0) && (errno == ENOSPC)) break; // 改变缓冲区大小 sendcount1 += send1; totalread1 -= send1; sprintf(msgbuf, "[%d] fd2成功在地址: %16s:%d上面发送%d字节\r\n", sock->idx, host2, port2, send1); outprint(msgbuf, strlen(msgbuf)); } // 检验出错 if (err == 1) break; // 如果发送了数据, 并且没有发送干净 if ((totalread1 > 0) && (sendcount1 > 0)) { // 理论上下面两行永远不会执行 memcpy(send_out1, send_out1 + sendcount1, totalread1); memset(send_out1 + totalread1, 0, MAXSIZE - totalread1); } else { memset(send_out1, 0, MAXSIZE); } } // fd2可读, 只要可读, 一次即可读取完整, 无需while循环 if (FD_ISSET(sock->fd2, &readfd) && totalread2 < MAXSIZE) { int read2 = recv(sock->fd2, read_in2, MAXSIZE - totalread2, 0); if (read2 == 0 || (read2 < 0 && errno != EINTR)) { sprintf(msgbuf, "[%d] Error: 读取fd2出错\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); break; } // 接了就立即发出去 memcpy(send_out2 + totalread2, read_in2, read2); sprintf(msgbuf, "[%d] fd2成功在地址: %16s:%d上面读取%d字节\r\n", sock->idx, host2, port2, read2); outprint(msgbuf, strlen(msgbuf)); totalread2 += read2; memset(read_in2, 0, MAXSIZE); } // fd1可写 if (FD_ISSET(sock->fd1, &writefd)) { int err2 = 0; int sendcount2 = 0; while (totalread2 > 0) { int send2 = send(sock->fd1, send_out2 + sendcount2, totalread2, 0); if (send2 == 0 || (send2 < 0 && errno != EINTR)) { sprintf(msgbuf, "[%d] Error: 写入fd1出错\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); err2 = 1; break; } if ((send2 < 0) && (errno == ENOSPC)) break; sendcount2 += send2; totalread2 -= send2; sprintf(msgbuf, "[%d] fd1成功在地址: %16s:%d上面发送%d字节\r\n", sock->idx, host1, port1, send2); outprint(msgbuf, strlen(msgbuf)); } if (err2 == 1) break; if ((totalread2 > 0) && (sendcount2 > 0)) { memcpy(send_out2, send_out2+sendcount2, totalread2); memset(send_out2 + totalread2, 0, MAXSIZE - totalread2); } else { memset(send_out2, 0, MAXSIZE); } } } // 关闭socket closesocket(sock->fd1); closesocket(sock->fd2); sprintf(msgbuf, "[%d] 成功关闭掉两个socket, fd1, fd2\r\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); sprintf(msgbuf, "[%d] 本次数据转发结束\r\n\n", sock->idx); outprint(msgbuf, strlen(msgbuf)); } ```
linux socket 端口问题
主机IP: 192.168.1.14 公网:1.2.3.4 路由器映射到外网端口:8888 socket 服务器bind 端口:1234 ,地址只能用 1.2.3.4:8888 外网的客户端 绑定地址 和 端口 分别应该是什么,
MAC 下端口复用为啥不起作用
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); MAC无论启用多线程还是多进程的端口复用,只有一个线程/进程处理数据,在linux下没问题,是MAC的限制吗?
java 客户端Socket端口问题
tcp问题,客户端Socket提问,getLocalPort(),连接的是本地的服务端,第一次运行是2880,第二次运行是2881,第三次运行是2882,我想了解客户端的端口是怎么回事,端口是怎么分配的?
java socket 端口转发遇到的问题
下面的程序运行之后,没有办法通过8081端口连上数据库服务器,这是为什么呢 package mis.client; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import lcc.SysLog; public class Client { public static void main(String[] args) throws Exception { Socket toDb = new Socket("10.11.112.48", 1521); ServerSocket serverServer = new ServerSocket(8081); Socket toServer = serverServer.accept(); InputStream toDbInStream = toDb.getInputStream(); OutputStream toDbOutStream = toDb.getOutputStream(); InputStream toServerInStream = toServer.getInputStream(); OutputStream toServerOutStream = toServer.getOutputStream(); System.out.println("客户端初始化完成"); pipe(toDbInStream,toServerInStream,toServerOutStream,toDbOutStream); } private static void pipe(InputStream is0, InputStream is1, OutputStream os0,OutputStream os1) { try { int ir; byte bytes[] = new byte[1024]; System.out.println(0); while (true) { try { if ((ir = is0.read(bytes)) > 0) { System.out.println(1); os0.write(bytes, 0, ir); } else if (ir < 0) { break; } } catch (InterruptedIOException e) { System.out.println("error--1"); } try { if ((ir = is1.read(bytes)) > 0) { System.out.println(2); os1.write(bytes, 0, ir); } else if (ir < 0) { break; } } catch (InterruptedIOException e) { System.out.println("error--2"); } } } catch (Exception e0) { } } } 补充:我程序的意图是把目标服务器1521端口的的数据转发的本地8081端口上,然后我用plsql工具去连库,程序只负责转发数据,现在的情况是数据没有转发过来
C# 关于Socket忽略证书的443端口连接问题
this.sslStream = new SslStream(this._client.GetStream(), false, new RemoteCertificateValidationCallback(this.CheckValidationResult), null); try { this.sslStream.AuthenticateAsClient(serverip, null, SslProtocols.Tls, false); } ......... 最近在做一个socket的项目,服务器是外部的(无法下载证书),上面的代码是反编译以前的客户端程序,异步socket在证书部分直接传的null,但是测试始终显示握手失败。请问下大家有这么方面的经验么?是因为我用的同步socket引起的问题吗?
BS结构中,浏览器使用的端口能否指定
在CS结构中如建立socket连接,我可以设置客户端和服务端的端口号,但是在BS结构的程序中,比如我写一个asp.net的程序,我只能设定服务的端口(5001),测试了一下浏览器的端口号似乎是随机的(5424、5425等),每次重开浏览器端口会变化。 ![图片说明](https://img-ask.csdn.net/upload/202001/16/1579137060_246554.png) 想请问一下浏览器使用哪个端口是如何确定的,能不能通过程序或浏览器设置的方式人工指定为特定的端口,或者一个范围? 如果不能指定的,防火墙如果禁用了大部分端口,怎么保证浏览器使用的那个端口一定能通过防火墙呢?
java和c使用socket通信时,发送报文的问题
问题详细描述:java是客户端,c语言是服务端。程序的目的是java发送报文过去 ,服务器能够识别。但是c语言写的服务端是很多年前的,目前已经无法对服务端作任何修改,c接收报文是用char定义的,报文是定长报文,不够的用空格补全,格式为包头+报文长度+报文内容(1字节+4字节+300字节),包头是6,报文长度是0300,报文内容由下图的结构体定义。![图片说明](https://img-ask.csdn.net/upload/201912/23/1577087403_15537.png)java使用getBytes()方法,获取了字节数组,发送过去后服务端报错,报错信息为包头错误,后来发现那边接收的是6对应ASCII码,请问这应该如何解决呢?java测试代码如下 ``` package Demo01; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class send { public static void main(String[] args) { try { iSend("172.33.xx.xx",10000); } catch (IOException e) { e.printStackTrace(); } } public static void iSend(String IP,int PORT) throws IOException{ String baotou = "6"; String blen= "0300"; String id = "0001"; String sysid = "1111"; String sysname = "disk"; String type = "11"; String level = "1"; String content = "sendcontent"; Socket socket = null; BufferedOutputStream bos = null; String message = "" ; List <Object> messList = new ArrayList(); messList.add(baotou); messList.add(blen); messList.add(id); messList.add(sysid); messList.add(sysname); messList.add(type); messList.add(level); messList.add(content); List <Object> messList2 = new ArrayList(); messList2.add(changeString(messList.get(0).toString(),1)); messList2.add(changeString(messList.get(1).toString(),4)); messList2.add(changeString(messList.get(2).toString(),4)); messList2.add(changeString(messList.get(3).toString(),8)); messList2.add(changeString(messList.get(4).toString(),16)); messList2.add(changeString(messList.get(5).toString(),16)); messList2.add(changeString(messList.get(6).toString(),16)); messList2.add(changeString(messList.get(7).toString(),240)); for(Iterator<Object> it = messList2.iterator();it.hasNext();){ message += it.next(); } System.out.println("报文为:"+message); try { socket = new Socket(IP,PORT); bos = new BufferedOutputStream(socket.getOutputStream()); byte [] buf = message.getBytes(); bos.write(buf,0,buf.length); bos.flush(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(socket != null){ socket.close(); } } } /** * *设置定长报文,用空格补齐 * @param object 报文集合 * @param len 报文的规定长度 * @return */ public static String changeString(String list,int len){ for(int ListLen = list.length();ListLen < len;ListLen++){ list +=" "; } return list; } } ```
Socket 无线通信 问题
1.这几天公司来了一个无线通信项目表示以前没做过啊 查阅了网上很多资料大致分为两种情况,下面 代码是其中一种的 也是百试不同,首先我们先确保设备是完好的 ,用网络调试助手先测一下。 ![图片说明](https://img-ask.csdn.net/upload/201912/21/1576917952_983775.jpg) 发送框内一串命令发出后 可以收到设备给返回的另一串返回值,这说明设备是没有问题的。那么我们进入到程序中。 我们先把输入值写死,以下为代码 ``` public class TestDemo3 { public static void main(String[] args) throws UnknownHostException, IOException { try { Socket socket; socket = new Socket("192.168.1.7",23); System.out.println("连接成功!"); OutputStream os=socket.getOutputStream(); PrintWriter pw=new PrintWriter(os); String sendInfo="01 03 0451 0001 D4 EB"; pw.write(sendInfo); System.out.println("发送成功!"); pw.flush(); socket.shutdownOutput(); String replyInfo=null; InputStream is=socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); System.out.println(br.readLine()); while(!((replyInfo=br.readLine())==null)){ System.out.println("接收服务器的数据信息:"+replyInfo); } br.close(); is.close(); pw.close(); os.close(); socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } ``` 这基本也是网上抄的其中一种,返回的值却为null 这说明没有接收到端口返回的值或者发送的值错误。有很多不解还请各位网络通信大神指点一二。
通过Socket访问IP端口号是否开启?
我想知道指定IP的端口号是否打开,如是通过Socket 建立连接,通过返回值来判断 指定IP的端口号是否打开,但是问题来了,如果打打开了,然后马上shutdown和close。 再通过例外的一个程序来建立socket并读取端口中数据,发现此时读取不到数据,应该 是上一个程序的端口并没有马上释放??求大神解答。
C#通过Socket实现多文件传输
大概需求是客户端发送一个xml文件名给服务器,服务器返回xml文件。这一步没问题。 后面客户端需要解析xml文件,根据解析出的文件名,去服务器获取指定文件。现在问题是第一次服务器发送xml文件之后就侦听不到客户端后面的请求了 服务端代码: ``` #region 窗体加载 private void Form1_Load(object sender, EventArgs e) { Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//Socket设置、IPv4、Stream类型套接字、TCP协议 IPAddress ip = IPAddress.Any;//获取本机IP IPEndPoint point = new IPEndPoint(ip, 18002);//设置IP和端口 socketWatch.Bind(point);//绑定端口 memoEdit1.Text = "开始侦听..."; socketWatch.Listen(100);//最大连接数 Thread th = new Thread(SendFileFuncssss);//创建新线程 th.Start(socketWatch);//启动线程 th.IsBackground = true;//设置后台运行线程 } #endregion #region 根据客户端传输文件名发送指定文件 public void SendFileFuncssss(object obj) { Socket socket = obj as Socket; while (true) { Socket socketServices = socket.Accept(); byte[] buffer = new byte[1024]; int num = socketServices.Receive(buffer);//接收到字节数 string str = Encoding.UTF8.GetString(buffer, 1, num - 1);//接收到字符串 if (buffer[0] == 0)//表示接收到的是消息数据 { TxtAddContent(socketServices.RemoteEndPoint + "连接成功"); string FileName = str; if (FileName.Equals("AutoUpdater.xml"))//获取xml配置文件 { //发送XML文件到客户端 using (FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + FileName, FileMode.Open)) { byte[] arrFile = new byte[1024 * 1024 * 5]; int length = fs.Read(arrFile, 0, arrFile.Length); byte[] arrFileSend = new byte[length + 1]; arrFileSend[0] = 1; // 用来表示发送的是xml文件数据 Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length); socketServices.Send(arrFileSend);// 发送数据到客户端 } } if (!FileName.Equals("AutoUpdater.xml")) { //发送更新文件到客户端 using (FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "\\FileFolder\\" + FileName, FileMode.Open)) { byte[] arrFile = new byte[1024 * 1024 * 50]; int length = fs.Read(arrFile, 0, arrFile.Length);//获取文件长度 byte[] arrFileSend = new byte[length + 1]; arrFileSend[0] = 1; // 用来表示发送的是xml文件数据 Buffer.BlockCopy(arrFile, 0, arrFileSend, 1, length); socketServices.Send(arrFileSend);// 发送数据到服务端 } } } } } #endregion ``` 客户端代码: ``` Socket socketClient = obj as Socket; socketClient.Connect(ipEndPoint); #region 修改本地文件名称 string Oldpath = AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater.xml";//修改前名称 string Newpath = AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater_Back.xml";//修改后名称 if (File.Exists(Oldpath)) { File.Delete(Newpath); File.Move(Oldpath, Newpath);//更改文件名 } #endregion if (socketClient.Connected) { try { TxtReceiveAddContent("连接成功"); //发送链接成功提示 byte[] arrMsg = Encoding.UTF8.GetBytes("AutoUpdater.xml"); byte[] arrSendMsg = new byte[arrMsg.Length + 1];//加一位标识用于表示是文字消息还是文件 arrSendMsg[0] = 0; // 用来表示发送的是消息数据 Buffer.BlockCopy(arrMsg, 0, arrSendMsg, 1, arrMsg.Length); socketClient.Send(arrSendMsg); //获取文件 string dirPath = Application.StartupPath; byte[] buffer = new byte[1024 * 1024 * 5]; int lenght = socketClient.Receive(buffer); if (buffer[0] == 1) { using (FileStream fs = new FileStream(dirPath + "\\AutoUpdater.xml", FileMode.Create)) { fs.Write(buffer, 1, lenght - 1); } TxtReceiveAddContent("配置文件接收成功:AutoUpdater.xml");//追加提示备注 } #region 获取XML里需要更新的文件和需要删除的文件 List<string> updatelist = new List<string>();//需要更新的文件集合 List<string> deletelist = new List<string>();//需要更新的文件集合 //获取历史xml文件更新时间以及更新版本 XDocument Olddocument = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater_Back.xml"); //获取到XML的根元素进行操作 XElement Oldroot = Olddocument.Root; XElement Oldele = Oldroot.Element("UpdateInfo"); //获取旧更新时间标签的值 XElement OldUpdateTime = Oldele.Element("UpdateTime"); //获取旧版本号标签的值 XElement OldVersion = Oldele.Element("Version"); //获取最新xml文件更新时间以及更新版本 XDocument Newdocument = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "AutoUpdater.xml"); //获取到XML的根元素进行操作 XElement Newroot = Newdocument.Root; XElement Newele = Newroot.Element("UpdateInfo"); //获取旧更新时间标签的值 XElement NewUpdateTime = Newele.Element("UpdateTime"); //获取旧版本号标签的值 XElement NewVersion = Newele.Element("Version"); if (NewUpdateTime != OldUpdateTime || NewVersion != OldVersion) { //获取需要更新的文件列表 XElement NewUpList = Newroot.Element("UpdateList"); IEnumerable<XElement> UpList = NewUpList.Elements(); foreach (XElement item in UpList) { updatelist.Add(item.Value); } //获取需要删除的文件列表 XElement NewDelList = Newroot.Element("DeleteList"); IEnumerable<XElement> DelList = NewDelList.Elements(); foreach (XElement item in DelList) { deletelist.Add(item.Value); } } #endregion #region 循环获取更新文件 for (int i = 0; i < updatelist.Count; i++) { //发送链接成功提示 byte[] FileName = Encoding.UTF8.GetBytes(updatelist[i]); byte[] SendFileName = new byte[FileName.Length + 1];//加一位标识用于表示是文字消息还是文件 SendFileName[0] = 0; // 用来表示发送的是消息数据 Buffer.BlockCopy(FileName, 0, SendFileName, 1, FileName.Length); socketClient.Send(SendFileName); //获取文件 string FilePath = Application.StartupPath + "\\WebFile"; byte[] bufferByFile = new byte[1024 * 1024 * 50]; int lenghtByFile = socketClient.Receive(bufferByFile); if (bufferByFile[0] == 1) { using (FileStream fs = new FileStream(FilePath + "\\" + updatelist[i], FileMode.Create)) { fs.Write(bufferByFile, 1, lenghtByFile - 1); } TxtReceiveAddContent("文件接收成功:" + updatelist[i]); } } #endregion #region 循环删除指定文件 for (int i = 0; i < deletelist.Count; i++) { try { string path = AppDomain.CurrentDomain.BaseDirectory + "\\WebFile\\" + deletelist[i]; File.Delete(path); TxtReceiveAddContent("删除文件[" + deletelist[i] + "]成功"); } catch (Exception) { TxtReceiveAddContent("删除文件[" + deletelist[i] + "]失败"); continue; } } #endregion } catch (Exception ex) { File.Move(Newpath, Oldpath);//连接失败,还原文件名 MessageBox.Show(ex.ToString()); throw; } ``` 调试在客户端进循环的时候服务端侦听不到了 刚接触socket,多谢大佬们解答
在socket中,如何让客户端固定它的端口
我想在socket通信中,让server能判断clinet连上来的是谁。 通常我们写socket通信时,server都这这样写的java: ``` ServerSocket server = new ServerSocket(9090); socket = server.accept(); ``` c++ qt中: ``` tcpserver = new QTcpServer(); tcpserver->listen(QHostAddress::Any,9090); connect(tcpserver,SIGNAL(newConnection()),this,SLOT(connected())); ``` 客户端java和c++都是差不多的。 可是当客户端链接到server时,同一个客户端每次链接所用的端口都是不同的。如何让client链接到server的端口固定下来,不要每次都随机。 我打算用这个实现判断客户端是谁。或者有没有其他更好的办法。
这是一个关于pyhton端口扫描器的问题
``` import socket import time for i in range(1,1000,1): try: quest = socket.socket(socket.AF_INET, socket.SOCK_STREAM) quest.settimeout(0.6) quest.connect(('127.0.0.1',i)) print(i,'端口','打开') quest.close() except : continue ``` 这是我写的一个端口扫描器,代码没报错。但是扫不出打开的端口,特奇怪。我用cmd看命令控制台,明明有几个1到1000内端口开着的
求大神来解答啊,关于C#socket编程的问题
需求描述: 使用C#开发一个服务端使用的是wpf项目,该服务端为手机客户端提供不同的访问URL,根据手机端访问服务器所使用的URL不同做出不同的回应,当然什么URL做出什么回应是由协商好的API决定的。 问题描述: 问题一:如何提供可以访问服务器同一端口的不同URL???我该怎么监听? 问题二:当有连接请求的时候我怎么指导手机端是使用了什么URL访问的??我能获取到URL吗?用什么方法? 问题三:以上问题解决方案能够在socket编程中解决吗?
TCP连接时,服务端监听socket接收客户端连接后新创建的socket默认绑定的端口是监听端口吗?
比如用来监听连接的socket绑定23端口,服务端每接受一个连接都新开一个线程和客户端通信,并把新socket传递给新线程,是不是所有新创建的socket都是经过23端口和客户端通信?
关于java tcp套接字setReuseAddress的问题
本来想做个tcp的net穿透,但是端口复用就出问题了。都说setReuseAddress设置为true的话可以实现端口复用,可是 Socket socket1 = new Socket(); Socket socket2 = new Socket(); socket1.setReuseAddress(true); socket2.setReuseAddress(true); socket1.bind(new InetSocketAddress("127.0.0.1", 88)); socket2.bind(new InetSocketAddress("127.0.0.1", 88)); 这样还是报Address already in use的错误,难道是java版本的问题?
c++,socket编程实现简易聊天系统,客户端一直连不上服务端,connect返回错误10014
客户端 ``` //建立线程 DWORD WINAPI ConnectThreadFunc(LPVOID pParam) { //初始化 WSAData wsData; if (!AfxSocketInit(&wsData)) { AfxMessageBox(_T("Socket 库初始化出错!")); return false; } CMFCApplication1View *pChatClient = (CMFCApplication1View*)pParam; ASSERT(pChatClient != NULL); //新建一个socket pChatClient->ConnectSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET==pChatClient->ConnectSock ) { AfxMessageBox(_T("创建socket失败!")); return FALSE; } AfxMessageBox(_T("成功创建socket")); //获取端口 CString ServeIp; pChatClient->GetDlgItemText(IDC_SERVEID_INPUT, ServeIp); //取服务端的IP地址 int SPort = pChatClient->GetDlgItemInt(IDC_SERVEPORT_INPUT); //获取端口 if (SPort <= 0 || SPort > 65535) { AfxMessageBox(_T("请输入合法的端口:1-65535")); goto _End; } AfxMessageBox(_T("端口合法")); //将IP转换 char AddrIp[16] = { 0 }; //窄字节 USES_CONVERSION; strcpy_s(AddrIp, 16, T2A(ServeIp)); // T2A:宏,进行字符串的转换 //将服务器的信息放入通用套接字中 sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(SPort); server.sin_addr.s_addr = inet_addr("192.168.73.1"); //客户端连接服务端 //将server传给connect if ( SOCKET_ERROR == connect(pChatClient->ConnectSock, (struct sockaddr*)&server, sizeof(struct sockaddrr*)) ) { /* char ErrorInfo[256] = { 0 }; //创建数组存储错误信息 sprintf_s(ErrorInfo, "Creat Faile : %d", GetLastError()); //把错误信息写入数组 AfxMessageBox((CString)ErrorInfo); */ AfxMessageBox(_T("连接失败!")); goto _End; } pChatClient->MsgShow(_T("服务器连接成功!")); while (TRUE) { if (SOCKERT_Select(pChatClient->ConnectSock,100,TRUE)) { char szBuf[MAX_BUF_SIZE] = { '0' }; //缓冲区 int iRet = recv(pChatClient->ConnectSock, szBuf, MAX_BUF_SIZE, 0); //recv()用来接收远程主机通过套接字sockfd发送来的数据, //并把这些数据保存到数组buf中 if (iRet > 0) { pChatClient->MsgShow((CString)szBuf); } else { pChatClient->MsgShow(_T("连接异常,请重新连接!")); break; } } Sleep(100); } _End: closesocket(pChatClient->ConnectSock); return TRUE; } ``` 服务端 ``` SOCKET ComSock; //用于发送消息 //查看客户端是否发来消息,并快速返回 BOOL SOCKERT_Select(SOCKET Socket, int TimeOut, BOOL bRead) { fd_set fdset; //通知执行了select()的进程哪一socket或文件发生了可读或可写事件 //long类型的数组,每一个数组元素都能与一打开的文件句柄建立联系 timeval tv; //判断是否超时,用于select()函数 FD_ZERO(&fdset); //清空集合中所有的元素 FD_SET(Socket, &fdset); //设置hSocket,使集合包含hSocket,即建立联系 TimeOut = TimeOut > 1000 ? 1000 : TimeOut; tv.tv_sec = 0; //秒数 tv.tv_usec = TimeOut; //微秒数 int iRet = 0; if (bRead) { //select()测试指定的fd可读?可写?有异常条件待处理? //即对socket操作 iRet = select(0, &fdset, NULL, NULL, &tv); } //读 else { iRet = select(0, NULL, &fdset, NULL, &tv); } //写 if (iRet <= 0) { //返回错误时 return FALSE; } else if (FD_ISSET(Socket, &fdset)) {//返回处于就绪状态并且已经包含在fd_set结构中的描述字总数 return TRUE; } return FALSE; //返回零时(超时返回零) } //通过线程来开启服务器,因为accept是阻塞的 //线程函数 DWORD WINAPI LisenThreadFunc(LPVOID pParam) { //LPVOID :32位的无类型的指针,在使用的时候再强制转换成需要的类型 CMFCApplication1View *pChatClient = (CMFCApplication1View*)pParam; //强制转换 ASSERT(pChatClient != NULL); //保证指针不为空 //断言函数,表达式为假则退出程序,为真继续执行 //用socket函数创建一个socket,用于监听 //成功则返回一个socket pChatClient->ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (pChatClient->ListenSock == INVALID_SOCKET) { AfxMessageBox(_T("创建socket失败!")); return 0; } //绑定,将 ListenSock 绑定在本地的一个ip和端口上 //1、动态获取用户输入的端口 int Port = pChatClient->GetDlgItemInt(IDC_LISTENPORT_INPUT); if (Port <= 0 || Port > 65535) { AfxMessageBox(_T("请输入合适的端口:1-65535")); goto _End; } //2、建立通用套接字 sockaddr_in service; //一种通用的套接字地址。用来建立所需信息,最后使用类型转换 //一般用于bind、connect、recvfrom、sendto等函数的参数 service.sin_family = AF_INET; //协议族 service.sin_addr.s_addr = inet_addr("127.0.0.1"); //获取本机所有可能得到的ip地址 service.sin_port = htons(Port); //传递端口 //htons:将主机字节顺序转换为网络字节顺序 //3、利用bind进行绑定 if (bind(pChatClient->ListenSock, (sockaddr*)&service, sizeof(sockaddr_in)) == SOCKET_ERROR) { AfxMessageBox(_T("绑定失败!")); goto _End; } AfxMessageBox(_T("绑定成功!")); //监听 if (listen(pChatClient->ListenSock, 4) == SOCKET_ERROR) { AfxMessageBox(_T("监听失败!")); goto _End; } //服务器已搭建完毕,开始进行消息监测 while (TRUE) { if (SOCKERT_Select(pChatClient->ListenSock, 1000, TRUE)) {//若有消息 sockaddr_in ClientSocket; int len = sizeof(sockaddr_in); //返回客户端(即对方)的IP地址和端口 SOCKET ComSock = accept(pChatClient->ListenSock, (struct sockaddr*)&ClientSocket, &len); if (ComSock == INVALID_SOCKET) { //若没有收到信息 continue; } //当要进行信息交互时,再建一个新线程来进行信息交互 // CMFCApplication1View *ClientCopy; HANDLE iTtem; iTtem = CreateThread(NULL, 0, ClientThreadProc, pChatClient, CREATE_SUSPENDED, NULL); pChatClient->comThread = iTtem; ResumeThread(iTtem); //恢复线程的执行 } Sleep(100); } _End: closesocket(pChatClient->ListenSock); //强制关闭socket return TRUE; } ``` 由于最近刚学socket,实在不知道怎么改了,请各位大神帮我康康,谢谢大家!(呜呜呜我是新手么的c币)
c# socket接收空包的问题
我现在遇到一个socket切换通道的一个问题,一共2个socket通道,1个是长连接,另一个是用完后断开在去连接主socket,就是那个长连接的,在回到主通道的时候向服务器发送socket指令的时候收到空包,而服务器回包没有错,我这边就首次回到主通道发送socket指令有问题,后续都正常,求大神赐教这是神马问题。
关于C#socket编程的一个小问题,欢迎大神来解答
需求描述: 使用C#开发一个服务端使用的是wpf项目,该服务端为手机客户端提供不同的访问URL,根据手机端访问服务器所使用的URL不同做出不同的回应,当然什么URL做出什么回应是由协商好的API决定的。 问题描述: 问题一:如何提供可以访问服务器同一端口的不同URL???我该怎么监听? 问题二:当有连接请求的时候我怎么指导手机端是使用了什么URL访问的??我能获取到URL吗?用什么方法? 问题三:以上问题解决方案能够在socket编程中解决吗?
PHP SOCKET如何释放所占用的端口
请问一下Linux上我用socket(在windows正常)但是每次都提醒占用端口 需要释放 所以我试了下在绑定前加上socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) 但是这样不但不行 而且客
Java学习的正确打开方式
在博主认为,对于入门级学习java的最佳学习方法莫过于视频+博客+书籍+总结,前三者博主将淋漓尽致地挥毫于这篇博客文章中,至于总结在于个人,实际上越到后面你会发现学习的最好方式就是阅读参考官方文档其次就是国内的书籍,博客次之,这又是一个层次了,这里暂时不提后面再谈。博主将为各位入门java保驾护航,各位只管冲鸭!!!上天是公平的,只要不辜负时间,时间自然不会辜负你。 何谓学习?博主所理解的学习,它是一个过程,是一个不断累积、不断沉淀、不断总结、善于传达自己的个人见解以及乐于分享的过程。
大学四年自学走来,这些私藏的实用工具/学习网站我贡献出来了
大学四年,看课本是不可能一直看课本的了,对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。主要有:电子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站。 注意:文中提到的所有资源,文末我都给你整理好了,你们只管拿去,如果觉得不错,转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...
linux系列之常用运维命令整理笔录
本博客记录工作中需要的linux运维命令,大学时候开始接触linux,会一些基本操作,可是都没有整理起来,加上是做开发,不做运维,有些命令忘记了,所以现在整理成博客,当然vi,文件操作等就不介绍了,慢慢积累一些其它拓展的命令,博客不定时更新 free -m 其中:m表示兆,也可以用g,注意都要小写 Men:表示物理内存统计 total:表示物理内存总数(total=used+free) use...
Vue + Spring Boot 项目实战(十四):用户认证方案与完善的访问拦截
本篇文章主要讲解 token、session 等用户认证方案的区别并分析常见误区,以及如何通过前后端的配合实现完善的访问拦截,为下一步权限控制的实现打下基础。
比特币原理详解
一、什么是比特币 比特币是一种电子货币,是一种基于密码学的货币,在2008年11月1日由中本聪发表比特币白皮书,文中提出了一种去中心化的电子记账系统,我们平时的电子现金是银行来记账,因为银行的背后是国家信用。去中心化电子记账系统是参与者共同记账。比特币可以防止主权危机、信用风险。其好处不多做赘述,这一层面介绍的文章很多,本文主要从更深层的技术原理角度进行介绍。 二、问题引入 假设现有4个人...
程序员接私活怎样防止做完了不给钱?
首先跟大家说明一点,我们做 IT 类的外包开发,是非标品开发,所以很有可能在开发过程中会有这样那样的需求修改,而这种需求修改很容易造成扯皮,进而影响到费用支付,甚至出现做完了项目收不到钱的情况。 那么,怎么保证自己的薪酬安全呢? 我们在开工前,一定要做好一些证据方面的准备(也就是“讨薪”的理论依据),这其中最重要的就是需求文档和验收标准。一定要让需求方提供这两个文档资料作为开发的基础。之后开发...
网页实现一个简单的音乐播放器(大佬别看。(⊙﹏⊙))
今天闲着无事,就想写点东西。然后听了下歌,就打算写个播放器。 于是乎用h5 audio的加上js简单的播放器完工了。 演示地点演示 html代码如下` music 这个年纪 七月的风 音乐 ` 然后就是css`*{ margin: 0; padding: 0; text-decoration: none; list-...
Python十大装B语法
Python 是一种代表简单思想的语言,其语法相对简单,很容易上手。不过,如果就此小视 Python 语法的精妙和深邃,那就大错特错了。本文精心筛选了最能展现 Python 语法之精妙的十个知识点,并附上详细的实例代码。如能在实战中融会贯通、灵活使用,必将使代码更为精炼、高效,同时也会极大提升代码B格,使之看上去更老练,读起来更优雅。
数据库优化 - SQL优化
以实际SQL入手,带你一步一步走上SQL优化之路!
2019年11月中国大陆编程语言排行榜
2019年11月2日,我统计了某招聘网站,获得有效程序员招聘数据9万条。针对招聘信息,提取编程语言关键字,并统计如下: 编程语言比例 rank pl_ percentage 1 java 33.62% 2 cpp 16.42% 3 c_sharp 12.82% 4 javascript 12.31% 5 python 7.93% 6 go 7.25% 7 p...
通俗易懂地给女朋友讲:线程池的内部原理
餐盘在灯光的照耀下格外晶莹洁白,女朋友拿起红酒杯轻轻地抿了一小口,对我说:“经常听你说线程池,到底线程池到底是个什么原理?”
经典算法(5)杨辉三角
杨辉三角 是经典算法,这篇博客对它的算法思想进行了讲解,并有完整的代码实现。
腾讯算法面试题:64匹马8个跑道需要多少轮才能选出最快的四匹?
昨天,有网友私信我,说去阿里面试,彻底的被打击到了。问了为什么网上大量使用ThreadLocal的源码都会加上private static?他被难住了,因为他从来都没有考虑过这个问题。无独有偶,今天笔者又发现有网友吐槽了一道腾讯的面试题,我们一起来看看。 腾讯算法面试题:64匹马8个跑道需要多少轮才能选出最快的四匹? 在互联网职场论坛,一名程序员发帖求助到。二面腾讯,其中一个算法题:64匹...
面试官:你连RESTful都不知道我怎么敢要你?
干货,2019 RESTful最贱实践
SQL-小白最佳入门sql查询一
不要偷偷的查询我的个人资料,即使你再喜欢我,也不要这样,真的不好;
项目中的if else太多了,该怎么重构?
介绍 最近跟着公司的大佬开发了一款IM系统,类似QQ和微信哈,就是聊天软件。我们有一部分业务逻辑是这样的 if (msgType = "文本") { // dosomething } else if(msgType = "图片") { // doshomething } else if(msgType = "视频") { // doshomething } else { // doshom...
漫话:什么是平衡(AVL)树?这应该是把AVL树讲的最好的文章了
这篇文章通过对话的形式,由浅入深带你读懂 AVL 树,看完让你保证理解 AVL 树的各种操作,如果觉得不错,别吝啬你的赞哦。 1、若它的左子树不为空,则左子树上所有的节点值都小于它的根节点值。 2、若它的右子树不为空,则右子树上所有的节点值均大于它的根节点值。 3、它的左右子树也分别可以充当为二叉查找树。 例如: 例如,我现在想要查找数值为14的节点。由于二叉查找树的特性,我们可...
“狗屁不通文章生成器”登顶GitHub热榜,分分钟写出万字形式主义大作
一、垃圾文字生成器介绍 最近在浏览GitHub的时候,发现了这样一个骨骼清奇的雷人项目,而且热度还特别高。 项目中文名:狗屁不通文章生成器 项目英文名:BullshitGenerator 根据作者的介绍,他是偶尔需要一些中文文字用于GUI开发时测试文本渲染,因此开发了这个废话生成器。但由于生成的废话实在是太过富于哲理,所以最近已经被小伙伴们给玩坏了。 他的文风可能是这样的: 你发现,...
程序员:我终于知道post和get的区别
是一个老生常谈的话题,然而随着不断的学习,对于以前的认识有很多误区,所以还是需要不断地总结的,学而时习之,不亦说乎
《程序人生》系列-这个程序员只用了20行代码就拿了冠军
你知道的越多,你不知道的越多 点赞再看,养成习惯GitHub上已经开源https://github.com/JavaFamily,有一线大厂面试点脑图,欢迎Star和完善 前言 这一期不算《吊打面试官》系列的,所有没前言我直接开始。 絮叨 本来应该是没有这期的,看过我上期的小伙伴应该是知道的嘛,双十一比较忙嘛,要值班又要去帮忙拍摄年会的视频素材,还得搞个程序员一天的Vlog,还要写BU...
开源并不是你认为的那些事
点击上方蓝字 关注我们开源之道导读所以 ————想要理清开源是什么?先要厘清开源不是什么,名正言顺是句中国的古代成语,概念本身的理解非常之重要。大部分生物多样性的起源,...
加快推动区块链技术和产业创新发展,2019可信区块链峰会在京召开
11月8日,由中国信息通信研究院、中国通信标准化协会、中国互联网协会、可信区块链推进计划联合主办,科技行者协办的2019可信区块链峰会将在北京悠唐皇冠假日酒店开幕。   区块链技术被认为是继蒸汽机、电力、互联网之后,下一代颠覆性的核心技术。如果说蒸汽机释放了人类的生产力,电力解决了人类基本的生活需求,互联网彻底改变了信息传递的方式,区块链作为构造信任的技术有重要的价值。   1...
程序员把地府后台管理系统做出来了,还有3.0版本!12月7号最新消息:已在开发中有github地址
第一幕:缘起 听说阎王爷要做个生死簿后台管理系统,我们派去了一个程序员…… 996程序员做的梦: 第一场:团队招募 为了应对地府管理危机,阎王打算找“人”开发一套地府后台管理系统,于是就在地府总经办群中发了项目需求。 话说还是中国电信的信号好,地府都是满格,哈哈!!! 经常会有外行朋友问:看某网站做的不错,功能也简单,你帮忙做一下? 而这次,面对这样的需求,这个程序员...
网易云6亿用户音乐推荐算法
网易云音乐是音乐爱好者的集聚地,云音乐推荐系统致力于通过 AI 算法的落地,实现用户千人千面的个性化推荐,为用户带来不一样的听歌体验。 本次分享重点介绍 AI 算法在音乐推荐中的应用实践,以及在算法落地过程中遇到的挑战和解决方案。 将从如下两个部分展开: AI算法在音乐推荐中的应用 音乐场景下的 AI 思考 从 2013 年 4 月正式上线至今,网易云音乐平台持续提供着:乐屏社区、UGC...
【技巧总结】位运算装逼指南
位算法的效率有多快我就不说,不信你可以去用 10 亿个数据模拟一下,今天给大家讲一讲位运算的一些经典例子。不过,最重要的不是看懂了这些例子就好,而是要在以后多去运用位运算这些技巧,当然,采用位运算,也是可以装逼的,不信,你往下看。我会从最简单的讲起,一道比一道难度递增,不过居然是讲技巧,那么也不会太难,相信你分分钟看懂。 判断奇偶数 判断一个数是基于还是偶数,相信很多人都做过,一般的做法的代码如下...
《C++ Primer》学习笔记(六):C++模块设计——函数
专栏C++学习笔记 《C++ Primer》学习笔记/习题答案 总目录 https://blog.csdn.net/TeFuirnever/article/details/100700212 —————————————————————————————————————————————————————— 《C++ Primer》习题参考答案:第6章 - C++模块设计——函数 文章目录专栏C+...
8年经验面试官详解 Java 面试秘诀
作者 |胡书敏 责编 | 刘静 出品 | CSDN(ID:CSDNnews) 本人目前在一家知名外企担任架构师,而且最近八年来,在多家外企和互联网公司担任Java技术面试官,前后累计面试了有两三百位候选人。在本文里,就将结合本人的面试经验,针对Java初学者、Java初级开发和Java开发,给出若干准备简历和准备面试的建议。 Java程序员准备和投递简历的实...
面试官如何考察你的思维方式?
1.两种思维方式在求职面试中,经常会考察这种问题:北京有多少量特斯拉汽车?某胡同口的煎饼摊一年能卖出多少个煎饼?深圳有多少个产品经理?一辆公交车里能装下多少个乒乓球?一个正常成年人有多少根头发?这类估算问题,被称为费米问题,是以科学家费米命名的。为什么面试会问这种问题呢?这类问题能把两类人清楚地区分出来。一类是具有文科思维的人,擅长赞叹和模糊想象,它主要依靠的是人的第一反应和直觉,比如小孩...
so easy! 10行代码写个"狗屁不通"文章生成器
前几天,GitHub 有个开源项目特别火,只要输入标题就可以生成一篇长长的文章。 背后实现代码一定很复杂吧,里面一定有很多高深莫测的机器学习等复杂算法 不过,当我看了源代码之后 这程序不到50行 尽管我有多年的Python经验,但我竟然一时也没有看懂 当然啦,原作者也说了,这个代码也是在无聊中诞生的,平时撸码是不写中文变量名的, 中文...
知乎高赞:中国有什么拿得出手的开源软件产品?(整理自本人原创回答)
知乎高赞:中国有什么拿得出手的开源软件产品? 在知乎上,有个问题问“中国有什么拿得出手的开源软件产品(在 GitHub 等社区受欢迎度较好的)?” 事实上,还不少呢~ 本人于2019.7.6进行了较为全面的回答,对这些受欢迎的 Github 开源项目分类整理如下: 分布式计算、云平台相关工具类 1.SkyWalking,作者吴晟、刘浩杨 等等 仓库地址: apache/skywalking 更...
相关热词 c# 输入ip c# 乱码 报表 c#选择结构应用基本算法 c# 收到udp包后回包 c#oracle 头文件 c# 序列化对象 自定义 c# tcp 心跳 c# ice连接服务端 c# md5 解密 c# 文字导航控件
立即提问