折腾了一个早上在原来的kinect程序上写一个远程发送图片功能,把截图用socket发送出去,才实现windows下两程序的对话。
主要参考了两篇博客,鞠躬感谢两位作者:
http://blog.csdn.net/u010477528/article/details/41680425
http://www.cnblogs.com/wainiwann/archive/2012/05/22/socket.html
server服务器端
此处把原来的kinect程序当成服务器端,改写了一下界面,加了一个远程连接按钮和发送输入框和发送按钮。
添加头文件 #include “winsock2.h”
SOCKET listen_sock;
SOCKET sock;
添加socket线程处理函数
UINT Server_Th(LPVOID p)
{
WSADATA wsaData;
WORD wVersion;
wVersion = MAKEWORD(2, 2);
WSAStartup(wVersion, &wsaData);
SOCKADDR_IN local_addr;
SOCKADDR_IN client_addr;
int iaddrSize = sizeof(SOCKADDR_IN);
int res;
char msg[1024];
CopentestDlg * dlg = (CopentestDlg *)AfxGetApp()->GetMainWnd();
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(5150);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if ((listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
dlg->pEdit->ReplaceSel(_T("创建监听失败\r\n"));
}
if (bind(listen_sock, (struct sockaddr*) &local_addr, sizeof(SOCKADDR_IN)))
{
dlg->pEdit->ReplaceSel(_T("绑定错误\r\n"));
}
listen(listen_sock, 1);
if ((sock = accept(listen_sock, (struct sockaddr *)&client_addr, &iaddrSize)) == INVALID_SOCKET)
{
dlg->pEdit->ReplaceSel(_T("accept 失败\r\n"));
}
else
{
CString port;
int temp = ntohs(client_addr.sin_port);
port.Format(_T("%d"), temp);
//port.Format("%d", int(ntohs(client_addr.sin_port)));
dlg->pEdit->ReplaceSel(_T("已连接来自:") + CString(inet_ntoa(client_addr.sin_addr)) + _T(" 端口:") + port+"\r\n");
}
//接收数据
while (1)
{
if ((res = recv(sock, msg, 1024, 0)) == -1)
{
dlg->pEdit->ReplaceSel(_T("失去连接\r\n"));
break;
}
else
{
msg[res] = '\0';
dlg->pEdit->ReplaceSel(_T("client:" + CString(msg)) + "\r\n");
}
}
return 0;
}
修改初始化部分OnInitDialog(),添加代码
此处是用来获取本机地址及初始化socket
AfxBeginThread(&Server_Th, 0); //初始化socket
send_edit = (CEdit *)GetDlgItem(IDC_ESEND);
send_edit->SetFocus();
char name[80];
CString IP;
hostent * pHost;
WSADATA wsData;
::WSAStartup(MAKEWORD(2, 2), &wsData);
//获得主机名
if (gethostname(name, sizeof(name)))
{
pEdit->ReplaceSel(_T("无法获取本机地址"));
return TRUE;
}
pHost = gethostbyname(name);//获得主机结构
IP = inet_ntoa(*(in_addr *)pHost->h_addr);
pEdit->ReplaceSel(_T("本机地址")+IP+ "\r\n");
发送文字消息
发送文字消息的处理比较简单,就是获取字符转成char *后发送
void CopentestDlg::OnBnClickedConnect()
{
CString str;
char * msg;
send_edit->GetWindowText(str);
USES_CONVERSION; //cstring 转char*
msg = T2A(str);
if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR)
{
pEdit->ReplaceSel(_T("发送失败\r\n"));
}
else if (str == "")
{
AfxMessageBox(_T("请输入信息"));
}
else
{
pEdit->ReplaceSel(_T("server:") + str + _T("\r\n"));//消息上屏,清空输入,并重获焦点
send_edit->SetWindowText(_T(""));
send_edit->SetFocus();
}
}
远程连接发送图片
远程连接按钮主要是用来发送从kinect截图的图片,这里主要思想是先告诉客户端“我要发送图片啦”,客户端收到讯息后进入准备接收图片的状态,然后服务器发送图片文件大小,客户端收到图片大小后,根据图片大小循环接收图片。
void CopentestDlg::OnBnClickedRemote()
{
HANDLE hFile;
hFile = CreateFile(CString(colorImagePath.c_str()), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
unsigned long long file_size = 0;
file_size = GetFileSize(hFile, NULL);
char buffer[BUFFER_SIZE];
const char * str= "准备发送图片";
//发送准备发送命令
memset(buffer, 0, BUFFER_SIZE);
strncpy(buffer, str, strlen(str));
if (send(sock, buffer, strlen(str), 0) == SOCKET_ERROR)
{
pEdit->ReplaceSel(_T("发送失败\r\n"));
return;
}
else
{
pEdit->ReplaceSel(_T("server:准备发送图片\r\n"));//消息上屏,清空输入,并重获焦点
}
//发送图片长度
memset(buffer, 0, sizeof(buffer));
memcpy(buffer, &file_size, sizeof(file_size) + 1);
if (send(sock, buffer, sizeof(file_size) + 1, 0) == SOCKET_ERROR)
{
pEdit->ReplaceSel(_T("发送失败\r\n"));
return;
}
else
{
pEdit->ReplaceSel(_T("开始发送图片\r\n"));//消息上屏,清空输入,并重获焦点
}
memset(buffer, 0, sizeof(buffer));
DWORD dwNumberOfBytesRead;
do
{
::ReadFile(hFile, buffer, sizeof(buffer), &dwNumberOfBytesRead, NULL);
::send(sock, buffer, dwNumberOfBytesRead, 0);
} while (dwNumberOfBytesRead);
CloseHandle(hFile);
pEdit->ReplaceSel(_T("成功发送图片\r\n"));
}
客户端
这里的客户端是重新写了一个mfc程序。界面是这样的
初始化函数进行一些基本的控件获取和设置,这里把ip填成服务器端获取的ip就可以了
// TODO: 在此添加额外的初始化代码
edit_show = (CEdit *)GetDlgItem(IDC_ESHOW);
edit_send = (CEdit *)GetDlgItem(IDC_ESEND);
btn_conn = (CButton *)GetDlgItem(IDC_BCONNECT);
edit_ip = (CEdit *)GetDlgItem(IDC_EIP);
edit_ip->SetWindowText(_T("192.168.31.1"));
if (!AfxSocketInit())
{
AfxMessageBox(_T("失败"));
return FALSE;
}
连接按钮
点击连接后,就可以创建socket并连接到服务器端,然后开启接收线程
void CsocketClientDlg::OnBnClickedBconnect()
{
WSADATA wsaData;
SOCKADDR_IN server_addr;
WORD wVersion;
wVersion = MAKEWORD(2, 2);
WSAStartup(wVersion, &wsaData);
CString ip;
edit_ip->GetWindowText(ip);//取得服务器的IP地址
USES_CONVERSION; //cstring 转char*
server_addr.sin_addr.s_addr = inet_addr(T2A(ip));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5150);
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
edit_show->ReplaceSel(_T("创建socket失败\r\n"));
}
if (connect(sock, (struct sockaddr *) &server_addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
edit_show->ReplaceSel(_T("连接失败\r\n"));
}
else
{
edit_show->ReplaceSel(_T("连接成功\r\n"));
AfxBeginThread(&Recv_Th, 0);//开启接收线程
btn_conn->EnableWindow(FALSE);//按钮变灰
}
}
消息发送按钮
与服务器的消息发送类似
// TODO: 在此添加控件通知处理程序代码
CString str;
char * msg;
edit_send->GetWindowText(str);
USES_CONVERSION; //cstring 转char*
msg = T2A(str);
if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR)
{
Update(_T("发送失败"));
}
else if (str == "")
{
AfxMessageBox(_T("请输入信息"));
}
else
{
Update(_T("client:") + str);//消息上屏,清空输入,并重获焦点
edit_send->SetWindowText(_T(""));
edit_send->SetFocus();
}
接收数据和图片
这部分就比较复杂了,主要是要区分一下图片接收部分和普通消息的接收部分。通过判断服务器发送的命令是否是“准备发送图片”来进入接收图片循环。根据图片大小接收图片。
UINT Recv_Th(LPVOID p)
{
int res;
char msg[1024];
unsigned long long file_size = 0; //文件的大小
CString str;
CsocketClientDlg * dlg = (CsocketClientDlg *)AfxGetApp()->GetMainWnd();
dlg->Update(_T("Initialization"));
const char * flag = "准备发送图片";
const char * filename = "./images/cut.png";
char buffer[BUFFER_SIZE];
while (1)
{
if ((res = recv(sock, msg, 1024, 0)) == -1)
{
dlg->Update(_T("失去连接"));
return 0;
}
else
{
msg[res] = '\0';
if (strcmp(msg,flag)==0) {
dlg->Update(_T("服务器要发送图片了,准备接收"));
if ((res = recv(sock, (char*)&file_size, sizeof(unsigned long long) + 1, NULL)) == -1)
{
dlg->Update(_T("失去连接"));
return 0;
}
else {
unsigned short maxvalue = file_size; //此处不太稳妥 当数据很大时可能会出现异常
dlg->Update(_T("开始接收图片"));
HANDLE hFile;
hFile = CreateFile(CString(filename), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwNumberOfBytesRecv = 0;
DWORD dwCountOfBytesRecv = 0;
memset(buffer, 0, BUFFER_SIZE);
//接收图片
do
{
dwNumberOfBytesRecv = ::recv(sock, buffer, sizeof(buffer), 0);
::WriteFile(hFile, buffer, dwNumberOfBytesRecv, &dwNumberOfBytesRecv, NULL);
dwCountOfBytesRecv += dwNumberOfBytesRecv;
} while (file_size - dwCountOfBytesRecv);
CloseHandle(hFile);
dlg->Update(_T("文件接收成功"));
}
}
else
{
dlg->Update(_T("server:") + CString(msg));
}
}
}
return 0;
}