mfc socket发送和接收数据和文件
来源:互联网 发布:linux vim命令模式 编辑:程序博客网 时间:2024/05/17 01:01
折腾了一个早上在原来的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;}
- mfc socket发送和接收数据和文件
- 异步 SOCKET 编程 - 发送和接收数据
- 异步 SOCKET 编程 - 发送和接收数据
- 异步SOCKET编程-发送和接收数据
- 异步 SOCKET 编程 - 发送和接收数据
- 异步 SOCKET 编程 - 发送和接收数据
- 异步SOCKET编程-发送和接收数据
- 异步SOCKET编程-发送和接收数据
- 使用Socket类接收和发送数据
- 异步 SOCKET 编程 - 发送和接收数据
- 使用Socket类接收和发送数据
- socket数据的接收和发送
- 8、socket数据的接收和发送
- 异步SOCKET编程-发送和接收数据[转] 异步SOCKET编程-发送和接收数据[转]
- Java实现XMPP发送接收消息和文件功能
- Socket 接收和发送数据的深刻理解.
- [转]异步SOCKET编程-发送和接收数据
- 异步SOCKET编程-发送和接收数据[转]
- Dijstra
- python 基础(三)一些要点回顾和字典 (和一些重点)
- Andriodjie——简单的购物车全选反选
- modelsim新建工程进行功能仿真
- 关于Unity渲染优化,你可能遇到这些问题
- mfc socket发送和接收数据和文件
- 训练GAN网络的技巧
- 计蒜客 课程规划(景驰无人驾驶1024编程邀请赛 D)
- 一分钟ECS上搭建云HBase Thriftserver
- 需要了解的相关知识
- QT安装问题
- 洛谷P1082 同余方程
- TensorFlow基本操作及函数
- spark 日常