Winsock客户端 - 通过TCP/IP4连接到网络摄像机
第一个:这是我在Stackoverflow上的第一篇文章(请让我,如果这是错误的子论坛,对不起),请原谅我的写作,因为英语不是我的本地语言。Winsock客户端 - 通过TCP/IP4连接到网络摄像机
所以,即时通讯尝试使用winsock(客户端 - 服务器聊天)来控制Windows应用程序的高速摄像头。摄像头通过以太网连接,它确实接受到给定端口的TCP连接。控制流被实现为TCP流套接字。
控制流语法:“控制流上的所有通信都是以文本(ASCII)格式完成的,这些命令被格式化以便人类输入命令并解释结果是合理的 控制流命令解释器读取命令行并生成响应行,对于每个命令行,只有一个响应行接收 换行使命令解释程序尝试执行自上一个换行符以来的所有输入作为命令响应(或错误)生成时,命令解释程序返回到它的基本状态 命令行被限制为总长度为65536字节(包括换行符),所有响应行保证不会超过相同的长度。
我已经能够与相机建立telnet连接并发送/接收消息。但是:我的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;
}
/////// ////////////////////////////////////////////////// //////////////////////
我不明白为什么它不工作,我在这里错过了什么吗?我很欣赏任何建议,谢谢!
干杯芬兰人
你说得很清楚:来自服务器的响应由简单的文本行,与尾部的换行符。
你的代码,尝试从套接字读取:
do {
rc = recv(sConnect, recvbuf, recvbuflen, 0);
// a few irrelevant details here
} while (rc > 0);
这将从套接字读取。从套接字读取内容后,它会继续读取。它会再次阅读,再次和一次。直到插座关闭。当您的相机厌倦了等待您发送评论并关闭套接字连接时,recv()
最终返回0,并且您的循环终止。万岁。
这显然不是你想要的。
您想从套接字中读取数据,直到读取到'\n'
,表示收到了整条线路。相应地,你必须在这里调整这个逻辑。
我确定您知道您不能保证一次完成recv()
整条生产线。如果响应的整行包含10个字符后跟一个换行符,则第一个拨打recv()
的电话可能会返回前五个字符,而第二个拨打电话recv()
会返回剩余的六个字符,第6个字符一个是换行符。您不知道宇宙射线是否导致摄像机的响应在网络上变得碎片化,主机从碎片数据包中接收摄像机的全部响应,并且recv()
每次返回一个数据包的有效负载。
您将需要修复您的逻辑,以便它可以持续读取套接字,每次将数据收集并附加到缓冲区中(而不是仅将所有内容放入同一缓冲区中,覆盖之前的recv()
结果),并且只有在检查收集到的缓冲区内容并找到换行符后才能终止循环。
您连接的同伴是否应该先发送内容?因为那第一次'recv'调用将*阻止*,否则。也许你应该改变'recv'和'send'的顺序? –