基于TCP的半关闭

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();
}










  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值