㈠ mfc socket tcp 多线程编程,一个服务器对多个客户端,跪求代码!
简单的就这样,收到一个连接请求,就生成一个socket负责与客户端通信,
㈡ 基于mfc的socket编程怎么进行文件传输
1. 采用了多线程的方法,文件传输时使用ad()开启新线程
void CClientsockDlg::OnBnClickedSend()
{
pThreadSend = AfxBeginThread(Thread_Send,this);/
}
文件的发送和接收都开起了新线程
UINTThread_Send(LPVOID lpParam)
{
代码略…
}
2. 支持从配置文件configuration.ini中获取服务器参数
采用GetPrivateProfileString()和GetPrivateProfileInt()分别获取位于ServerConfiguration.ini文件中的String类型的IP和int类型的port
CString IP;
int port;
GetPrivateProfileString
(L"ServerConfiguration",L"IP",L"没有读取到数据!",IP.GetBuffer(10),10,L".\\configuration.ini");
port=GetPrivateProfileInt(L"ServerConfiguration",L"port",0,L".\\configuration.ini");
3. 采用了面向对象的设计方式,功能之间按模块划分
MFC本身具有良好的面向对象的特性,本程序严格按照MFC框架结构编写代码,每个按钮对应一个功能函数,降低了代码之间的耦合性,有利于程序的扩展和复用。
void CServersockDlg::OnBnClickedChoose()
void CServersockDlg::OnBnClickedSend()
void CServersockDlg::OnBnClickedRecvdata()
void CServersockDlg::OnBnClickedAbout()
void CServersockDlg::OnBnClickedWriteini()
4. 采用了CSocket类,代码相对更简单
CSocket类是MFC框架对socket编程中的winsockAPI的封装,因此通过这个类管理收发数据更加便利。代码也跟那个既简单易懂。
//创建
if(!Clientsock.Socket())
{
CString str;
str.Format(_T("Socket创建失败:%d"),GetLastError());
AfxMessageBox(str);
}
//连接
if(!Clientsock.Connect(IP,port))
{
CString str;
str.Format(_T("Socket连接失败:%d"),GetLastError());
AfxMessageBox(str);
}
else
{
AfxMessageBox(_T("Socket连接成功"));
代码略…
//发送
while(nSize<FindFileData.nFileSizeLow)
{
szBuff = new char[1024];
memset(szBuff,0x00,1024);
nSend =file.Read(szBuff,1024);
Clientsock.Send(szBuff,nSend);//发送数据
nSize += nSend;
}
file.Close();
delete szBuff;
Clientsock.Close();
(dlg->GetDlgItem(IDC_SEND))->EnableWindow(TRUE);
AfxMessageBox(_T("文件发送成功"));
dlg->SetDlgItemTextW(IDC_FILEPATHNAME,_T(""));
}
return 0;
5. 支持数据在服务器与客户端之间双向传输
本程序不但可以从客户端往服务器端传文件,而且可以从服务器端往客户端传文件。
但是互传文件的方式并不是完全相同的。
服务器端不管是接收文件还是发送文件始终是对绑定的端口进行监听。
//绑定
if(!Serversock.Bind(port))
{
CString str;
str.Format(_T("Socket绑定失败: %d"),GetLastError());
AfxMessageBox(str);
}
//监听
if(!Serversock.Listen(10))
{
CString str;
str.Format(_T("Socket监听失败:%d"),GetLastError());
AfxMessageBox(str);
}
客户端不管是接收文件还是发送文件始终是进行连接。
if(!Clientsock.Connect(IP,port))
{
CString str;
str.Format(_T("Socket连接失ì败:%d"),GetLastError());
AfxMessageBox(str);
}
else
{
略…
6. 完全图形化操作界面
二.软件使用说明
客户端主界面如图所示:
单击“选择文件”弹出文件对话框,选择一个要发送的文件,同时保存文件的路径。
单击“发送”则会读取ServerConfiguration.ini文件中的配置信息(IP和port),并根据此信息建立Socket连接,发送文件。注意:服务器端应该先单击了“接受客户端数据”,否则发送失败。
单击“接收”也会读取ServerConfiguration.ini文件中的配置信息(IP和port),并根据此信息建立Socket连接,接收文件。注意:服务器端应该先选择了向客户端发送的文件,并单击了“发送”,否则接受失败。
单击“读取配置文件”,会从ServerConfiguration.ini文件中读取配置信息,并以可编辑的文本形式显示出来,修改完后,单击“写入配置文件”,会将修改后的信息保存到配置文件中。
单击“关于”可以了解到软件相关信息。
代码注释里有更详细的说明
服务器端主界面如图所示
u 单击“接受客户端数据”,开始监听客户端的链接。
u 单击“选择文件”弹出文件对话框,选择一个要发送的文件,同时保存文件的路径。
u 单击“发送”则会读取ServerConfiguration.ini文件中的配置信息(port),并监听对应端口,准备发送文件。注意:客户端选择“接收”以后才能发送成功。
u 单击“读取配置文件”,会从ServerConfiguration.ini文件中读取配置信息,并以可编辑的文本形式显示出来,修改完后,单击“写入配置文件”,会将修改后的信息保存到配置文件中。但是服务器的IP是不可以修改的,它是在程序开始运行时从服务器所在机器的网卡上获取的。
u 单击“关于”可以了解到软件相关信息。
u 代码注释里有更详细的说明
代码下载地址:http://download.csdn.net/detail/leixiaohua1020/6320417
在此附上客户端使用CSocket发起连接的代码
[cpp] view plain
//----------------------------发送文件的线程------------------------------
UINT Thread_Send(LPVOID lpParam)
{
CClientsockDlg *dlg=(CClientsockDlg *)lpParam;
(dlg->GetDlgItem(IDC_SEND))->EnableWindow(FALSE);
CSocket Clientsock; //definition socket.
if(!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
}
CString IP;
int port;
GetPrivateProfileString(L"ServerConfiguration",L"IP",L"没有读取到数据!",IP.GetBuffer(100),100,L".\\configuration.ini");
port=GetPrivateProfileInt(L"ServerConfiguration",L"port",0,L".\\configuration.ini");
//创建
if(!Clientsock.Socket())
{
CString str;
str.Format(_T("Socket创建失败: %d"),GetLastError());
AfxMessageBox(str);
}
//连接
// if(!Clientsock.Connect(_T("127.0.0.1"),8088))
if(!Clientsock.Connect(IP,port))
{
CString str;
str.Format(_T("Socket连接失败: %d"),GetLastError());
AfxMessageBox(str);
}
else
{
AfxMessageBox(_T("Socket连接成功"));
WIN32_FIND_DATA FindFileData;
CString strPathName; //定义用来保存发送文件路径的CString对象
dlg->GetDlgItemTextW(IDC_FILEPATHNAME,strPathName);
FindClose(FindFirstFile(strPathName,&FindFileData));
Clientsock.Send(&FindFileData,sizeof(WIN32_FIND_DATA));
CFile file;
if(!file.Open(strPathName,CFile::modeRead|CFile::typeBinary))
{
AfxMessageBox(_T("文件不存在"));
return 1;
}
UINT nSize = 0;
UINT nSend = 0;
char *szBuff=NULL;
//发送
while(nSize<FindFileData.nFileSizeLow)
{
szBuff = new char[1024];
memset(szBuff,0x00,1024);
nSend = file.Read(szBuff,1024);
Clientsock.Send(szBuff,nSend);//发送数据
nSize += nSend;
}
file.Close();
delete szBuff;
Clientsock.Close();
(dlg->GetDlgItem(IDC_SEND))->EnableWindow(TRUE);
AfxMessageBox(_T("文件发送成功"));
dlg->SetDlgItemTextW(IDC_FILEPATHNAME,_T(""));
}
return 0;
}
以及服务器端使用CSocket监听的代码:
[cpp] view plain
//----------------------------监听文件的线程------------------------------
UINT Thread_Func(LPVOID lpParam) //接收文件的线程函数
{
CServersockDlg *dlg = (CServersockDlg *)lpParam; //获取对话框指针
(dlg->GetDlgItem(IDC_RECVDATA))->EnableWindow(FALSE);
if(!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
}
CString IP;
int port;
GetPrivateProfileString(L"ServerConfiguration",L"IP",L"没有读取到数据!",IP.GetBuffer(100),100,L".\\configuration.ini");
port=GetPrivateProfileInt(L"ServerConfiguration",L"port",0,L".\\configuration.ini");
char errBuf[100]={0};// 临时缓存
SYSTEMTIME t; //系统时间结构
CFile logErrorfile;
if(!logErrorfile.Open(_T("logErrorfile.txt"),CFile::modeCreate|CFile::modeReadWrite))
{
return 1;
}
CSocket Serversock;
CSocket Clientsock;
//创建
if(!Serversock.Socket())
{
CString str;
str.Format(_T("Socket创建失败: %d"),GetLastError());
AfxMessageBox(str);
}
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
Serversock.SetSockOpt(SO_REUSEADDR,(void *)&bOptVal,bOptLen,SOL_SOCKET);
//绑定
if(!Serversock.Bind(port))
{
CString str;
str.Format(_T("Socket绑定失败: %d"),GetLastError());
AfxMessageBox(str);
}
//监听
if(!Serversock.Listen(10))
{
CString str;
str.Format(_T("Socket监听失败: %d"),GetLastError());
AfxMessageBox(str);
}
GetLocalTime(&t);
sprintf_s(errBuf,"服务器已经启动...正在等待接收文件...\r\n时间:%d年%d月%d日 %2d:%2d:%2d \r\n",t.wYear,t.wMonth,t.wDay,
t.wHour,t.wMinute,t.wSecond);
int len = strlen(errBuf);
logErrorfile.Write(errBuf,len);
AfxMessageBox(_T("启动成功等待接收文件"));
while(1)
{
//AfxMessageBox(_T("服务器启动成功..."));
if(!Serversock.Accept(Clientsock)) //等待接收
{
continue;
}
else
{
WIN32_FIND_DATA FileInfo;
Clientsock.Receive(&FileInfo,sizeof(WIN32_FIND_DATA));
CFile file;
file.Open(FileInfo.cFileName,CFile::modeCreate|CFile::modeWrite);
//AfxMessageBox(FileInfo.cFileName);
int length = sizeof(FileInfo.cFileName);
logErrorfile.Write(FileInfo.cFileName,length);
//Receive文件的数据
UINT nSize = 0;
UINT nData = 0;
char *szBuff=NULL;
while(nSize<FileInfo.nFileSizeLow)
{
szBuff = new char[1024];
memset(szBuff,0x00,1024);
nData=Clientsock.Receive(szBuff,1024);
file.Write(szBuff,nData);
nSize+=nData;
}
delete szBuff;
Serversock.Close();
Clientsock.Close();
file.Close();
(dlg->GetDlgItem(IDC_RECVDATA))->EnableWindow(TRUE);
sprintf_s(errBuf,"文件接收成功...\r\n时间:%d年%d月%d日 %2d:%2d:%2d \r\n",t.wYear,t.wMonth,t.wDay,
t.wHour,t.wMinute,t.wSecond);
int len = strlen(errBuf);
logErrorfile.Write(errBuf,len);
//AfxMessageBox(_T("文件接收成功..."));
break;
}
}
return 0;
}
㈢ mfc中用TCP/IP socket编程来写了一个简单的收发端,可客户端的accept()老连接不上
你的意思是不是服务端卡在accept()那,然后客户端弹出“连接失败!”窗口?
如果是这样的话先检查网络连接是否正常,然后IP是不是对的
如果以上都没问题,用WSAGetLastError()得到错误代码并在MessageBox()中显示。
另外发现你用阻塞方式收发数据,最好将这两段代码放入新线程,否则容易卡死
附上WSAGetLastError()错误代码:
WSAENOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。
WSAEADDRINUSE:所指的地址已在使用中。
WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。
WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。
WSAEADDRNOTAVAIL:在本地机器上找不到所指的地址。
WSAENOTSUPPORT:所指族中地址无法与本套接口一起使用。
WSAECONNREFUSED:连接尝试被强制拒绝。
WSAEDESTADDREQ:需要目的地址。
WSAEFAULT:namelen参数不正确。
WSAEINVAL:套接口没有准备好与一地址捆绑。
WSAEISCONN:套接口早已连接。
WSAEMFILE:无多余文件描述字。
WSAENETUNREACH:当前无法从本主机访问网络。
WSAENOBUFS:无可用缓冲区。套接口未被连接。
WSAENOTSOCK:描述字不是一个套接口。
WSAETIMEOUT:超时时间到。
WSAEWOULDBLOCK:套接口设置为非阻塞方式且连接不能立即建立。可用select()调用对套接口写,因为select()时会进行连接。
希望对你有帮肋..
㈣ mfc socket 编程的流程是怎么样的
初始化socket
首先需要调用AfxSocketInit()函数来初始化我们的socket环境。
为了初始化sockets,我们需要调用AfxSocketInit()函数。它通常是在MFC中的InitInstance()函数中被调用的。如果我们用程序向导来创建socket程序的话,查看“use Windows Sockets”这个选项,然后选中它。它将会自动的为我们创建这个步骤了。(如果我们没有选中这个选项的话,我们也可以手动添加这些代码的。)这个函数的返回值显示这个函数的调用成功或失败。
BOOL CServerApp::InitInstance()
{....
if( AfxSocketInit() == FALSE)
{
AfxMessageBox("Sockets Could Not Be Initialized");
return FALSE;
}
...
}
创建Server Sockets
为了创建一个Server Socket,我们需要声明一个CAyncSocket的变量或者我们自己定制的一个从AyncSocket或是Cscket继承来的类的类型的变量。然后调用Create()函数,同时指定监听的端口。这个函数的返回值显示这个函数的调用成功或失败。
UpdateData(TRUE);
m_sListener.Create(m_port);
if(m_sListener.Listen()==FALSE)
{
AfxMessageBox("Unable to Listen on that port,please try another port");
m_sListener.Close();
return;
}
创建Client Sockets
为了创建Client socket类,我们需要声明一个CAyncSocket的变量或者我们自己定制的一个从AyncSocket或是Cscket继承来的类的类型的变量。然后调用Create()函数,同时指定监听的端口。这个函数的返回值显示这个函数的调用成功或失败。
m_sConnected.Create();
m_sConnected.Connect("server ip",port);
监听客户端的连接
创建了server socket以后,我们要进行监听。调用Listen()函数。这个函数的返回值显示这个函数的调用成功或失败。
if( m_sListener.Listen()== FALSE)
{
AfxMessageBox("Unable to Listen on that port,please try another port");
m_sListener.Close();
return;
}
接受连接
连接请求要被接受accept,是用另外的socket,不是正在监听的socket。请参看代码。
void CXXXDlg::OnAccept()
{
CString strIP;
UINT port;
if(m_sListener.Accept(m_sConnected))
{
m_sConnected.GetSockName(strIP,port); //应该是GetPeerName,获取对方的IP和port
m_status="Client Connected,IP :"+ strIP;
m_sConnected.Send("Connected To Server",strlen("Connected To Server"));
UpdateData(FALSE);
}
else
{
AfxMessageBox("Cannoot Accept Connection");
}
}
发送数据
数据放在一个buffer中或是结构体中,调用send()函数发送。
m_sConnected.Send(pBuf,iLen);
接受数据
调用receive()接受数据。
void CXXXrDlg::OnReceive()
{
char *pBuf =new char [1025];
CString strData;
int iLen;
iLen=m_sConnected.Receive(pBuf,1024);
if(iLen == SOCKET_ERROR)
{
AfxMessageBox("Could not Recieve");
}
else
{
pBuf[iLen]=NULL;
strData=pBuf;
m_recieveddata.Insert(m_recieveddata.GetLength(),strData);
//display in server
UpdateData(FALSE);
m_sConnected.Send(pBuf,iLen); //send the data back to the Client
delete pBuf;
}
}
关闭连接
m_sConnected.ShutDown(0); 停止发送数据
m_sConnected.ShutDown(1); 停止接受数据
m_sConnected.ShutDown(2); 停止发送接受数据
m_sConnected.Close();
编写自己的socket类
在class view中选择添加一个新类,设置它的基类为CAsyncSocket,在类向导的帮助下添加如下的一些函数。
class MySocket : public CAsyncSocket
{ // Attributes
public:
// Operations
public:
MySocket();
virtual ~MySocket();
// Overrides
public:
void SetParentDlg(CDialog *pDlg);// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(MySocket)
public:
virtual void OnAccept(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnOutOfBandData(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual void OnSend(int nErrorCode);
//}}AFX_VIRTUAL // Generated message map functions
//{{AFX_MSG(MySocket)
// NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG
protected:
private:
CDialog * m_pDlg;
};
设置“Parent Dialog”
调用这个socket类的SetParentDlg函数,保证当socket事件发生的时候这个窗体能接收到。
m_sListener.SetParentDlg(this);
m_sConnected.SetParentDlg(this);
建立Socket 事件和窗体成员函数之间的联系
在这个窗体类中添加一些函数,比如void OnReceive(); void OnClose(); void OnAccept(); void OnConnect()等,它们会在我们编写的的socket类中调用到。
void MySocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
if(nErrorCode==0)
{
((CServerDlg*)m_pDlg)->OnAccept();
}
CAsyncSocket::OnAccept(nErrorCode);
}
㈤ mfc socket接收数据问题
m_pSocket->Create(m_localPortNum, SOCK_DGRAM); //m_localPortNum=5080
你选择的是UDP不是TCP所以得指定A机器的ip和端口,不过你也可以版直接connect后用权send发送(可以不指定IP和端口的)。