windows的closesocket函数意味着完全断开连接(单方面断开连接)。完全断开不仅指无法传输数据,而且也不能接受数据。因此,在某些情况下closesocket函数断开连接就显得不太适用。
为了解决这类问题,只关闭一部分数据交换中使用的流(half-close)的方法应运而生。断开一部分连接是指,可以传输数据但无法接收,或可以接收数据但无法传输。顾名思义就是只关闭流的一半。
套接字和流
两台主机通过套接字建立连接后进入可交换数据的状态,又称“流形成的状态”也就是把建立套接字后可交换数据的状态看作一种流。在套接字的流中,数据也只能向一个方向移动。
一旦两台主机间建立了套接字连接,每个主机就会拥有单独的输入流和输出流。当然,其中一个主机的输入流与另一个主机的输出流相连,而输出流则与另一主机的输入流相连,半关闭只断开其中一个流,closesocket将同时断开两个流。
服务端
#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define bufsize 1024
using namespace std;
void main() {
WSADATA wsadata;
SOCKET serverSocket,clientSocket;
int szClientAddr,fpCnt;
SOCKADDR_IN serverAddr, clientAddr;
char message[bufsize] = "\0";
FILE *f;
f = fopen("c:/1.txt", "rb" );
if(WSAStartup(MAKEWORD(2, 2), &wsadata)!=0)
cout<<"WSAStartup() error"<<endl;
serverSocket = socket(PF_INET, SOCK_STREAM, 0);
if(serverSocket == INVALID_SOCKET)
cout<<"socket() error"<<endl;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(9999);
if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
cout << "bind () error" << endl;
listen(serverSocket, 5);
cout << "服务器启动成功!" << endl;
szClientAddr = sizeof(clientAddr);
clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &szClientAddr);
if (clientSocket == INVALID_SOCKET) cout << "accept() error" << endl;
else cout << "已有客户端连接" << endl;
while (1) {
fpCnt = fread(message, 1, bufsize, f);
if (fpCnt < bufsize) {
send(clientSocket, message, fpCnt, 0); //发送小于bufsize的数据
break;
}
send(clientSocket, message, bufsize, 0);
}
shutdown(clientSocket, SD_SEND);
recv(clientSocket, message, bufsize, 0);
cout << "客户端消息" << message << endl;
fclose(f);
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
getchar();
}
客户端
#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define bufsize 1024
using namespace std;
void main() {
WSADATA wsadata;
SOCKET clientSocket;
SOCKADDR_IN serverAddr;
FILE *f;
int recvCnt;
f = fopen("c:/2.txt", "wb");
char message[bufsize] = "\0";
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
cout << "WSAStartup() error" << endl;
if ((clientSocket = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
cout << "socket() error" << endl;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddr.sin_port = htons(9999);
if(connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr))==SOCKET_ERROR)
cout<<"connect() error"<<endl;
while ((recvCnt=recv(clientSocket,message,bufsize,0))!=0) {
fwrite(message, 1, recvCnt, f);
}
cout << "接受数据完成!" << endl;
send(clientSocket, "thank you!", 11, 0);
fclose(f);
closesocket(clientSocket);
WSACleanup();
}