非阻塞套接字实现的文件传输程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非阻塞套接字实现的文件传输程序相关的知识,希望对你有一定的参考价值。

异步传输模式下(推荐WSAAnsyncSelect模式,也可用其他异步模式)可以实现点对点的文件传输(可以实现大文件1G以上传输)。

难点:
如何有序地传输文件块?即:异步模式下如何实现同步?
提示:可以编写一个协议来实现(类似FTP协议),发送方发送了一个块以后,接受到接受方关于这个块的确认后,再发送下一个。

如果实现多线程传输文件(可以同时收发文件)更好···

程序可用还可追加分数

以前写的有一些错误
希望能对你有些帮助

// TCPDlg.h : header file
//

#if !defined(AFX_TCPDLG_H__E2F8748A_67A9_47EA_981E_1A2A72E09154__INCLUDED_)
#define AFX_TCPDLG_H__E2F8748A_67A9_47EA_981E_1A2A72E09154__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CTCPDlg dialog
#define WM_CLIENT WM_USER + 101
#include "MyEdit.h"
#include "onnect.h"
#include "XPButton.h"
typedef struct ZyMsg
char control[1];
char filename[256];
int length;
Msg;
class CTCPDlg : public CDialog

// Construction
public:
BOOL Start;
void OUTEXception(int Error);
CTCPDlg(CWnd* pParent = NULL); // standard constructor
SOCKET COnnect;
Connect dlg;
int response;
Msg msg;
CMyEdit Edit1;
CMyEdit Edit2;
CXPButton Button1;
CXPButton Button2;
CXPButton Button3;
CXPButton Button4;
CXPButton Button5;
DWORD sytart;
BOOL rec;
// Dialog Data
//AFX_DATA(CTCPDlg)
enum IDD = IDD_TCP_DIALOG ;
// NOTE: the ClassWizard will add data members here
//AFX_DATA

// ClassWizard generated virtual function overrides
//AFX_VIRTUAL(CTCPDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//AFX_VIRTUAL

// Implementation
protected:
HICON m_hIcon;

// Generated message map functions
//AFX_MSG(CTCPDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton1();
afx_msg void OnButton2();
afx_msg void OnButton3();
afx_msg void OnButton4();
afx_msg void OnButton5();
//AFX_MSG
afx_msg void OnClient(WPARAM wParam,LPARAM lParam);
DECLARE_MESSAGE_MAP()
;

//AFX_INSERT_LOCATION
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_TCPDLG_H__E2F8748A_67A9_47EA_981E_1A2A72E09154__INCLUDED_)

// TCPDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TCP.h"
#include "TCPDlg.h"
#include "mmsystem.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog

public:
CAboutDlg();

// Dialog Data
//AFX_DATA(CAboutDlg)
enum IDD = IDD_ABOUTBOX ;
//AFX_DATA

// ClassWizard generated virtual function overrides
//AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//AFX_VIRTUAL

// Implementation
protected:
//AFX_MSG(CAboutDlg)
//AFX_MSG
DECLARE_MESSAGE_MAP()
;

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

//AFX_DATA_INIT(CAboutDlg)
//AFX_DATA_INIT


void CAboutDlg::DoDataExchange(CDataExchange* pDX)

CDialog::DoDataExchange(pDX);
//AFX_DATA_MAP(CAboutDlg)
//AFX_DATA_MAP


BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//AFX_MSG_MAP(CAboutDlg)
// No message handlers
//AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTCPDlg dialog

CTCPDlg::CTCPDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTCPDlg::IDD, pParent)

//AFX_DATA_INIT(CTCPDlg)
// NOTE: the ClassWizard will add member initialization here
//AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
Start=false;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);


void CTCPDlg::DoDataExchange(CDataExchange* pDX)

CDialog::DoDataExchange(pDX);
//AFX_DATA_MAP(CTCPDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//AFX_DATA_MAP


BEGIN_MESSAGE_MAP(CTCPDlg, CDialog)
//AFX_MSG_MAP(CTCPDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
ON_BN_CLICKED(IDC_BUTTON4, OnButton4)
ON_BN_CLICKED(IDC_BUTTON5, OnButton5)
//AFX_MSG_MAP
ON_MESSAGE(WM_CLIENT,OnClient)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTCPDlg message handlers

BOOL CTCPDlg::OnInitDialog()

CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)

CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())

pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);



// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
Edit1.SubclassDlgItem(IDC_EDIT1,this);
Edit2.SubclassDlgItem(IDC_EDIT2,this);
Button1.SubclassDlgItem(IDC_BUTTON1,this);
Button2.SubclassDlgItem(IDC_BUTTON2,this);
Button3.SubclassDlgItem(IDC_BUTTON3,this);
Button4.SubclassDlgItem(IDC_BUTTON4,this);
Button5.SubclassDlgItem(IDC_BUTTON5,this);
// TODO: Add extra initialization here
response=dlg.DoModal();
if(response!=IDOK)
this->OnOK();
this->COnnect=::socket(AF_INET,SOCK_STREAM,0);
sockaddr_in add;
add.sin_addr.S_un.S_addr = inet_addr(dlg.m_edit1);
add.sin_port=::htons(::atof(dlg.m_edit2.GetBuffer(dlg.m_edit2.GetLength())));
add.sin_family=AF_INET;
int timeout =5000*3;
setsockopt(this->COnnect,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout, // 设置接收超时
sizeof(timeout));
timeout = 5000*3;
setsockopt(this->COnnect,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout, sizeof(timeout)); //设置发送超时
response=::connect(this->COnnect,(sockaddr *)&add,sizeof(sockaddr_in));
if(response==SOCKET_ERROR)

AfxMessageBox("连接服务器失败");
int error=::GetLastError();
this->OUTEXception(error);

else

AfxMessageBox("连接服务器");

WSAAsyncSelect(this->COnnect,m_hWnd,WM_CLIENT,FD_READ);
int nRecvBuf=3200*1024;//设置为32K
response=setsockopt(this->COnnect,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
if(response==SOCKET_ERROR)

int error=::GetLastError();
this->OUTEXception(error);


return TRUE; // return TRUE unless you set the focus to a control


void CTCPDlg::OnSysCommand(UINT nID, LPARAM lParam)

if ((nID & 0xFFF0) == IDM_ABOUTBOX)

CAboutDlg dlgAbout;
dlgAbout.DoModal();

else

CDialog::OnSysCommand(nID, lParam);



// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CTCPDlg::OnPaint()

CPaintDC dc(this);
CBitmap a;
a.LoadBitmap(IDB_BITMAP3);
CBrush b(&a);
CRect rect;
GetClientRect(&rect);
dc.FillRect(&rect,&b);
if (IsIconic())

CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in Client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);

else

CDialog::OnPaint();



// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CTCPDlg::OnQueryDragIcon()

return (HCURSOR) m_hIcon;


void CTCPDlg::OnButton1()

// TODO: Add your control notification handler code here
CString str,s;
this->GetDlgItem(IDC_EDIT2)->GetWindowText(str);
str="客户端:"+str+"\r\n";;
msg.control[0]='M';
msg.length=str.GetLength();
response=::send(this->COnnect,(char *)&msg,sizeof(Msg),0);
response=::send(this->COnnect,str.GetBuffer(str.GetLength()),str.GetLength(),0);
if(response==SOCKET_ERROR)

int error=::GetLastError();
this->OUTEXception(error);

this->GetDlgItem(IDC_EDIT1)->GetWindowText(s);
str=s+str;
this->GetDlgItem(IDC_EDIT1)->SetWindowText(str);
this->GetDlgItem(IDC_EDIT2)->SetWindowText("");


void CTCPDlg::OUTEXception(int Error)

switch(Error)

case WSANOTINITIALISED:AfxMessageBox("A successful AfxSocketInit must occur before using this API.");break;
case WSAENETDOWN :AfxMessageBox("The Windows Sockets implementation detected that the network subsystem failed.");break;
case WSAEACCES:AfxMessageBox("The requested address is a broadcast address, but the appropriate flag was not set.");break;
case WSAEINPROGRESS:AfxMessageBox("A blocking Windows Sockets operation is in progress.");break;
case WSAEFAULT:AfxMessageBox("The lpBuf or lpSockAddr parameters are not part of the user address space,");break;
case WSAEINVAL:AfxMessageBox(" The host name is invalid.");break;
case WSAENETRESET:AfxMessageBox("The Cliention must be reset because the Windows Sockets implementation dropped it.");break;
case WSAENOBUFS :AfxMessageBox("The Windows Sockets implementation reports a buffer deadlock.");break;
case WSAENOTCONN:AfxMessageBox("The socket is not Cliented (SOCK_STREAM only).");break;
case WSAENOTSOCK:AfxMessageBox("The descriptor is not a socket.");break;
case WSAEOPNOTSUPP :AfxMessageBox(" MSG_OOB was specified, but the socket is not of type SOCK_STREAM");break;
case WSAESHUTDOWN:AfxMessageBox("The socket has been shut down;");break;
case WSAEWOULDBLOCK :AfxMessageBox("The socket is marked as nonblocking and the requested operation would block.");break;
case WSAEMSGSIZE :AfxMessageBox("The socket is of type SOCK_DGRAM, and the datagram is larger than the maximum supported by the Windows Sockets implementation.");break;
case WSAECONNABORTED:AfxMessageBox("The virtual circuit was aborted due to timeout or other failure.");break;
case WSAECONNRESET:AfxMessageBox("The virtual circuit was reset by the remote side.");break;
case WSAEADDRNOTAVAIL:AfxMessageBox("The specified address is not available from the local machine.");break;
case WSAEAFNOSUPPORT :AfxMessageBox("Addresses in the specified family cannot be used with this socket.");break;
case WSAEDESTADDRREQ:AfxMessageBox("A destination address is required.");break;
case WSAENETUNREACH :AfxMessageBox("The network cannot be reached from this host at this time.");break;
case WSAEADDRINUSE :AfxMessageBox("The specified address is already in use.");break;
case WSAECONNREFUSED :AfxMessageBox("The attempt to Client was rejected.");break;
case WSAEISCONN :AfxMessageBox("The socket is already Cliented.");break;
case WSAEMFILE :AfxMessageBox("No more file descriptors are available.");break;
case WSAETIMEDOUT:AfxMessageBox("Attempt to Client timed out without establishing a Cliention.");break;
case WSAEINTR:AfxMessageBox("The (blocking) Windows Socket 1.1 call was canceled through WSACancelBlockingCall.");break;
case WSAEALREADY: AfxMessageBox("A nonblocking Client call is in progress on the specified socket");break;
default:AfxMessageBox("不明原因");



void CTCPDlg::OnButton2()

// TODO: Add your control notification handler code here
CString str,s;
CFileDialog dlg(TRUE,NULL,NULL,NULL,"位图文件(*.bmp)|*.bmp|文本文件(*.txt)|*.txt|All Files(*.*)|*.*||");
if(dlg.DoModal()==IDOK)

str=dlg.GetPathName();
s=dlg.GetFileName();

else
return;
CFile f;
char buf[512];
int Read;
f.Open(str,CFile::modeReadWrite);
msg.control[0]='F';
msg.length=f.GetLength();
::strcpy(msg.filename,s.GetBuffer(s.GetLength()));
response=::send(this->COnnect,(char *)&msg,sizeof(Msg),0);
str="";
while(1)

Read=f.Read(buf,512);
if(Read==0)
break;
::send(this->COnnect,buf,Read,0);




void CTCPDlg::OnButton3()

// TODO: Add your control notification handler code here
msg.control[0]='C';
msg.length=1;
::send(this->COnnect,(const char *)&msg,sizeof(Msg),0);

void CTCPDlg::OnClient(WPARAM wParam,LPARAM lParam)

switch(WSAGETSELECTEVENT(lParam))

case FD_READ:
int read;
char lpBuf[2048];
CString str,m_Path;
char* A1="F";
char* A2="M";
char* A3="C";
CString s,t;
int re;
CFile f;
if(Start==false)

::WSAAsyncSelect(COnnect,m_hWnd,0,0);
::recv(COnnect,(char*)&msg,sizeof(Msg),0);
re=msg.length;
s=msg.control[0];
if(!::strcmp(s.GetBuffer(s.GetLength()),A1))

BROWSEINFO bi;
char name[MAX_PATH];
ZeroMemory(&bi,sizeof(BROWSEINFO));
bi.hwndOwner=GetSafeHwnd();
bi.pszDisplayName=name;
bi.lpszTitle="浏览文件夹";
bi.ulFlags=BIF_RETURNONLYFSDIRS;
LPITEMIDLIST idl=SHBrowseForFolder(&bi);
sytart=::GetTickCount();
if(idl==NULL)

rec=false;
m_Path="";

else

BOOL Sh=SHGetPathFromIDList(idl,str.GetBuffer(MAX_PATH));
str.ReleaseBuffer();
m_Path=str;
if(str.GetAt(str.GetLength()-1)!='\\')
m_Path+="\\";
UpdateData(FALSE);

m_Path=m_Path+msg.filename;
f.Open(m_Path,CFile::modeCreate|CFile::modeReadWrite);
Start=true;
::WSAAsyncSelect(COnnect,m_hWnd,WM_CLIENT,FD_READ);
int nRecvBuf=re;//设置为32K
response=setsockopt(COnnect,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
if(response==SOCKET_ERROR)

int error=::GetLastError();
this->OUTEXception(error);



if(Start)
while(1)

read=::recv(COnnect,(char*)lpBuf,2048,0);
if(read>0)

re=re-read;
f.Write(lpBuf,read);

if((::GetTickCount()-sytart)>5*60*1000)

Start=false;
AfxMessageBox("接收数据失败!!");
break;

if(read==SOCKET_ERROR&&::GetLastError()==WSAEWOULDBLOCK)

break;

if(read==SOCKET_ERROR&&::GetLastError()!=WSAEWOULDBLOCK)

Start=false;
AfxMessageBox("接收数据失败!!");
break;

if(re==0)

if(rec==false)
AfxMessageBox(msg.filename);
f.Close();
f.Remove(msg.filename);
rec=true;
Start=false;
break;

AfxMessageBox("接受数据完成");
Start=false;
f.Close();
break;


if(!::strcmp(s.GetBuffer(s.GetLength()),A2))

::sndPlaySound("msg.wav",SND_ASYNC);
read=::recv(COnnect,lpBuf,512,0);
t=lpBuf;
this->GetDlgItem(IDC_EDIT1)->GetWindowText(str);
str=str+t.Left(read);
if(!str.IsEmpty())
this->GetDlgItem(IDC_EDIT1)->SetWindowText(str);
AfxGetMainWnd()->FlashWindow(TRUE);
Start=false;
break;





void CTCPDlg::OnButton4()

// TODO: Add your control notification handler code here
msg.control[0]='C';
msg.length=2;
::send(this->COnnect,(const char *)&msg,sizeof(Msg),0);


void CTCPDlg::OnButton5()

// TODO: Add your control notification handler code here
msg.control[0]='C';
msg.length=3;
::send(this->COnnect,(const char *)&msg,sizeof(Msg),0);
参考技术A 大哥。你为什么不去C++里提问呢?那里高手很多!会很快帮你解决的! 参考技术B 嗯,好像我们的课程设计也是类似这个

留名关注下,说不定用得上^_^

java nio的实现原理

1 什么是java nio

java nio就是java非阻塞io。

2 什么是channel

channel是到打开的文件的连接,只要是支持读写操作的实体都可以称为文件,文件可以是硬件设备、文件和网络套接字等。

3 多路复用非阻塞IO的实现原理

3.1 Selector、selection keys和selectable channels一起来实现多路复用非阻塞IO。

3.2 什么是多路复用

多路指的是多个channel、复用指的是多个channel复用一个线程来进行数据的读写。

3.3 什么非阻塞IO

指的是被复用的线程是不会阻塞的,只要有chanel有数据,它就一直在工作,除非所有的路都没有数据。

3.4 Selector的背后的实现原理

4 noi buffers

为什么要弄这么多的nio buffer?nio buffer有什么用?

在进行标准io的时候因为只有一个chanel在用这个thread,因此不需要buffer,但是多个chanel复用的话,就会存在等待的chanel,这样的话,有一个buffer缓存一下,处理上会更加方便。

 

以上是关于非阻塞套接字实现的文件传输程序的主要内容,如果未能解决你的问题,请参考以下文章

在python中解析(流式传输)XML的非阻塞方法

操作系统-IO零拷贝

操作系统-IO零拷贝

操作系统-IO零拷贝

求一个C#最简单的TCP传输信息例子(实现聊天和传送文件,再简单点实现聊天也行)

网络编程Socket的阻塞和非阻塞IO