本文目录一览:
如何通过Socket TCP发送并接收一个文件
主要是你通过socket api封装要发送的数据,内部会自动封装成数据流进行传输。
1,什么是Socket
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。-socket传文件
但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
2,Socket通讯的过程
Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。-socket传文件
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
(1) 创建Socket;
(2) 打开连接到Socket的输入/出流;
(3) 按照一定的协议对Socket进行读/写操作;
(4) 关闭Socket.(在实际应用中,并未使用到显示的close,虽然很多文章都推荐如此,不过在我的程序中,可能因为程序本身比较简单,要求不高,所以并未造成什么影响。)
3,创建Socket
创建Socket
java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:
Socket(InetAddress address, int port);
Socket(InetAddress address, int port, boolean stream);
Socket(String host, int prot);
Socket(String host, int prot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, int port, InetAddress localAddr, int localPort)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddress bindAddr)
Socket client = new Socket("127.0.01.", 80);
ServerSocket server = new ServerSocket(80);
在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。
在JAVA的socket中进行传输对象和文件
服务端监听:ServerSocket server=new ServerSocket(port);//port:绑定的端口号
Socket client=server.accept();//监听端口,一旦取得连接则获得客户端的socket连接对象client
客户端: Socket s=new Socket(ip,port);//要连接的服务器的ip以及端口号
如果正常连接上之后,socket的对象可以获得InputStream和OutputStreame,然后就可以进行通信了
完成通信之后,执行socket对象的close()方法关闭连接,完成一次完整的socket连接
基于mfc的socket编程怎么进行文件传输
1. 采用了多线程的方法,文件传输时使用AfxBeginThread()开启新线程
void CClientsockDlg::OnBnClickedSend()
{
pThreadSend = AfxBeginThread(Thread_Send,this);/
}
文件的发送和接收都开起了新线程
UINTThread_Send(LPVOID lpParam)
{
代码略…
}
2. 支持从配置文件configuration.ini中获取服务器参数
采用GetPrivateProfileString()和GetPrivateProfileInt()分别获取位于ServerConfiguration.ini文件中的String类型的IP和int类型的port-socket传文件
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(nSizeFindFileData.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连接,发送文件。注意:服务器端应该先单击了“接受客户端数据”,否则发送失败。-socket传文件
单击“接收”也会读取ServerConfiguration.ini文件中的配置信息(IP和port),并根据此信息建立Socket连接,接收文件。注意:服务器端应该先选择了向客户端发送的文件,并单击了“发送”,否则接受失败。-socket传文件
单击“读取配置文件”,会从ServerConfiguration.ini文件中读取配置信息,并以可编辑的文本形式显示出来,修改完后,单击“写入配置文件”,会将修改后的信息保存到配置文件中。
单击“关于”可以了解到软件相关信息。
代码注释里有更详细的说明
服务器端主界面如图所示
u 单击“接受客户端数据”,开始监听客户端的链接。
u 单击“选择文件”弹出文件对话框,选择一个要发送的文件,同时保存文件的路径。
u 单击“发送”则会读取ServerConfiguration.ini文件中的配置信息(port),并监听对应端口,准备发送文件。注意:客户端选择“接收”以后才能发送成功。
u 单击“读取配置文件”,会从ServerConfiguration.ini文件中读取配置信息,并以可编辑的文本形式显示出来,修改完后,单击“写入配置文件”,会将修改后的信息保存到配置文件中。但是服务器的IP是不可以修改的,它是在程序开始运行时从服务器所在机器的网卡上获取的。-socket传文件
u 单击“关于”可以了解到软件相关信息。
u 代码注释里有更详细的说明
代码下载地址:
在此附上客户端使用CSocket发起连接的代码
[cpp] view plain copy
//----------------------------发送文件的线程------------------------------
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"); -socket传文件
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(nSizeFindFileData.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 copy
//----------------------------监听文件的线程------------------------------
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"); -socket传文件
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, -socket传文件
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(nSizeFileInfo.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, -socket传文件
t.wHour,t.wMinute,t.wSecond);
int len = strlen(errBuf);
logErrorfile.Write(errBuf,len);
//AfxMessageBox(_T("文件接收成功..."));
break;
}
}
return 0;
}
socket文件传输为什么数据会丢失
如果是自己设计的网络编程传输,因为socket缓冲区大小和应用层接收速度不一致,就会导致部分数据还没接受完,下一部分数据又到来。可以设计一个方法来确保数据一致。
网页链接
typedef struct
{
int len; //buf里面存放的数据长度
char buf[128];
}data,*pdada;
先发送服务器端读文件会返回读到的字节数,先给客户端发送这个,告诉他要接收多少字符,然后在发送数据。
void recv_n(int new_fd,char *buf,int len)
{
int ret;
int total = 0;
while(totallen)
{
ret = recv(new_fd,buf+total,len-total,0);
total += ret;
}
}