【问题标题】:Winsock Client - Connecting to a Network Camera via TCP/IP4Winsock 客户端 - 通过 TCP/IP4 连接到网络摄像机
【发布时间】:2017-05-02 05:21:01
【问题描述】:

第一个:这是我在 Stackoverflow 上的第一篇文章(如果这是错误的子论坛,请告诉我,对不起),请原谅我的写作,因为英语不是我的母语。

所以,我正在尝试使用 winsock(客户端-服务器聊天)通过 Windows 应用程序控制高速摄像机。相机通过以太网连接,它接受到给定端口的 TCP 连接。控制流被实现为 TCP 流套接字。

控制流语法:“控制流上的所有通信都以文本 (ASCII) 格式完成。命令的格式是这样的,因此人类可以合理地键入命令并解释结果。 控制流命令解释器读取命令行并生成重新 响应线。对于每个命令行,都只有一个响应行。接收 换行符会导致命令解释器尝试将自最后一个换行符以来的所有输入作为命令执行。在生成响应(或错误)后,命令解释器返回到它的基本状态。 命令行的总长度限制为 65536 字节(包括换行符)。保证所有响应行不超过相同的长度。”

我已经能够建立到相机的 telnet 连接并发送 /receive 消息。 但是:我的 c++ 客户端应用程序不会接收或发送任何消息。它表示连接已成功建立。

我使用的是 Windows 10 和 Visual Studio 2015;我的代码:

/////////////////////////////////////// ////////////////////////////

// TCP Client
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define DEFAULT_BUFLEN 512

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <cstdio>
#include <iostream>

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")

using namespace std;

int main()
{
int recvbuflen = DEFAULT_BUFLEN;
char sendbuf[512];
char recvbuf[DEFAULT_BUFLEN];
long rc;

WSADATA wsaData;
SOCKET sConnect = INVALID_SOCKET;
sockaddr_in serv_addr;

// ws2_32.dll activate
rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc == 0)
cout << "WSAStartup()\t\t successful" << endl;
else
cout << "error WSAStartup(): " << WSAGetLastError() << endl;

// socket configuration
sConnect = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET for IP4
if (sConnect != INVALID_SOCKET)
cout << "socket() \t\t successful" << endl;
else
cout << "error socket(): " << WSAGetLastError() << endl;

// connection info
serv_addr.sin_addr.s_addr = inet_addr("x.x.x.x"); //Camera IP
serv_addr.sin_family = AF_INET; //IP4
serv_addr.sin_port = htons(7200); //given Port
int conparlen = sizeof(serv_addr);


// connecting to server
rc = connect(sConnect, (struct sockaddr*)&serv_addr, conparlen);
if (rc != SOCKET_ERROR)
cout << "connect() \t\t successful" << endl;
else
cout << "not connected(): " << WSAGetLastError() << endl;

while (1)
{
//memset(&sendbuf, 0, sizeof(sendbuf)); Do I need this??
//memset(&recvbuf, 0, sizeof(recvbuf));

do {
rc = recv(sConnect, recvbuf, recvbuflen, 0);
if (rc > 0)
printf("Bytes received: %d\n", rc);
else if (rc == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (rc > 0);

cout << "send: ";
cin.getline(sendbuf, 512);
//sendbuf[rc] = '\0';

rc = send(sConnect, sendbuf, (int)strlen(sendbuf), 0);
if (rc == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(sConnect);
WSACleanup();
return 1;
}

printf("Bytes Sent: %ld\n", rc);

}

closesocket(sConnect);
WSACleanup();
return 0;
}

/////////////////////////////////////// ////////////////////////////

我不明白为什么它不起作用,我在这里遗漏了什么吗?感谢您的任何建议,谢谢!

芬恩干杯

【问题讨论】:

  • 您连接的对等方是否应该先发送一些东西?因为第一个 recv 调用将 block 否则。也许您应该更改recvsend 的顺序?

标签: c++ windows sockets tcp winsock


【解决方案1】:

您的指示非常清楚:来自服务器的响应由一行简单的文本组成,后面带有一个换行符。

您尝试从套接字读取的代码:

do {
rc = recv(sConnect, recvbuf, recvbuflen, 0);

// a few irrelevant details here

} while (rc > 0);

这将从套接字读取。从套接字读取某些内容后,...它将继续读取。它会再读一遍,一遍又一遍。直到套接字关闭。当您的相机厌倦了等待您发送评论并关闭套接字连接时,recv() 最终返回 0,并且您的循环终止。万岁。

这显然不是你想要的。

你想从套接字中读取,直到读取到'\n',表示接收到整行。您必须在此处相应地调整此逻辑。

我相信您也知道不能保证您同时recv() 整行。如果响应的整行由十个字符后跟一个换行符组成,例如,对recv() 的第一次调用可能会返回前五个字符,然后对recv() 的第二次调用将返回剩余的六个字符,第 6 个是换行符。您真的不知道宇宙射线是否导致您的相机的响应在网络上变得碎片化,您的主机以碎片数据包的形式接收来自相机的整个响应,recv() 返回每​​个单独数据包的有效负载,一个时间。

您将需要修复您的逻辑,以便它每次都从套接字读取,收集数据并将数据附加到缓冲区中(而不仅仅是recv()将所有内容放入同一个缓冲区,覆盖之前的@987654329 @ 的结果),只有在检查缓冲区的收集内容并找到换行符后才终止循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-17
    • 1970-01-01
    • 2017-08-23
    • 2017-11-23
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多