回射程序3(服务器)——客户服务器不定长接收数据

设计思路上一篇已经说明。

贴上服务器的代码:

// 回显服务器3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <string.h>

#pragma comment(lib,"wsock32.lib")
#define  SERVERPROT 6000
#define  MAXSIZE 100

//函数声明
int recvn(SOCKET s, char * recvbuf, unsigned int fixedlen);
int recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen);


int _tmain(int argc, _TCHAR* argv[])
{
	//初始化WinSock
	WSADATA wsaData;
	int ret = WSAStartup(MAKEWORD(2,2),&wsaData);
	if(ret!=0)
	{
		printf("WSAStartup() failed!code:%d\n",WSAGetLastError());
		return -1;
	}
	if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
	{
		WSACleanup();
		printf("Invalid WinSock Version\n");
		return -1;
	}
	//创建监听套接字
	SOCKET slisten;
	slisten = socket(AF_INET,SOCK_STREAM,0);
	if(slisten == INVALID_SOCKET)
	{
		printf("socket() failed!code:%d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}
	//构建服务器本地地址信息
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(SERVERPROT);
	serveraddr.sin_addr.S_un.S_addr =  INADDR_ANY;

	//绑定
	ret = bind(slisten,(sockaddr*)&serveraddr,sizeof(serveraddr));
	if(ret == SOCKET_ERROR)
	{
		printf("bind() failed!code:%d\n",WSAGetLastError());
		closesocket(slisten);
		WSACleanup();
		return -1;
	}
	//侦听连接请求
	ret = listen(slisten,5);
	if(ret == SOCKET_ERROR)
	{
		printf("listen() failed!code:%d\n",WSAGetLastError());
		closesocket(slisten);
		WSACleanup();
		return -1;
	}
	printf("waiting for client connecting...\n");
	//接收客户端连接
	struct sockaddr_in clientaddr;
	int clientaddrlen = sizeof(clientaddr);
	SOCKET sServer;//连接套接字
	char buff[MAXSIZE];//接收缓存
	char sendbuf[MAXSIZE];//发送缓存
	unsigned int slen=0; //发送数据长度
	unsigned int buflen=MAXSIZE;
	sServer = accept(slisten,(struct sockaddr*)&clientaddr,&clientaddrlen);
	if(sServer == INVALID_SOCKET)
	{
		printf("accept() failed!code:%d\n",WSAGetLastError());
		closesocket(slisten);
		WSACleanup();
		return -1;
	}
	while(TRUE)  //循环接收数据
	{
		memset(buff, 0 , MAXSIZE);
		memset(sendbuf,0,MAXSIZE);
		ret = recvvl(sServer,buff,buflen);
		if(ret==SOCKET_ERROR)
		{
			int nErrCode = WSAGetLastError();//错误代码
			if (WSAENOTCONN == nErrCode)
			{
				printf("The socket is not connected!\n");

			}else if(WSAESHUTDOWN == nErrCode)
			{
				printf("The socket has been shut down!\n");

			}else if (WSAETIMEDOUT == nErrCode)
			{
				printf("The connection has been dropped!\n");							
			}else if (WSAECONNRESET == nErrCode)
			{
				printf("The virtual circuit was reset by the remote side!\n");
			}else{}	
			closesocket(sServer);
			closesocket(slisten);
			WSACleanup();
			return -1;
		}
		sprintf(sendbuf,"echo:%s",buff);
		printf("%s\n",sendbuf);
		slen = (unsigned int)strlen(sendbuf);
		slen = htonl(slen);
		ret = send(sServer,(char*)&slen,sizeof(unsigned int),0);
		if (SOCKET_ERROR == ret)
		{
			int nErrCode = WSAGetLastError();//错误代码
			if (WSAENOTCONN == nErrCode)
			{
				printf("The socket is not connected!\n");

			}else if(WSAESHUTDOWN == nErrCode)
			{
				printf("The socket has been shut down!\n");

			}else if (WSAETIMEDOUT == nErrCode)
			{
				printf("The connection has been dropped!\n");
			}else{}	
			closesocket(sServer);
			closesocket(slisten);
			WSACleanup();
			return -1;
		}
		ret = send(sServer,sendbuf,strlen(sendbuf),0);
		if (SOCKET_ERROR == ret)
		{
			int nErrCode = WSAGetLastError();//错误代码
			if (WSAENOTCONN == nErrCode)
			{
				printf("The socket is not connected!\n");

			}else if(WSAESHUTDOWN == nErrCode)
			{
				printf("The socket has been shut down!\n");

			}else if (WSAETIMEDOUT == nErrCode)
			{
				printf("The connection has been dropped!\n");
			}else{}	
			closesocket(sServer);
			closesocket(slisten);
			WSACleanup();
			return -1;
		}


	}
	closesocket(sServer);
	closesocket(slisten);
	WSACleanup();
	return 0;
}


//指定长度接收
int recvn(SOCKET s, char * recvbuf, unsigned int fixedlen)
{
	int iResult;    //存储单次recv操作的返回值
	int cnt;         //用于统计相对于固定长度,剩余多少字节尚未接收
	cnt = fixedlen;
	while ( cnt > 0 ) {
		iResult = recv(s, recvbuf, cnt, 0);
		if ( iResult < 0 ){
			//数据接收出现错误,返回失败
			printf("接收发生错误: %d\n", WSAGetLastError());
			return -1;
		}
		if ( iResult == 0 ){
			//对方关闭连接,返回已接收到的小于fixedlen的字节数
			printf("连接关闭\n");
			return fixedlen - cnt;
		}
		//printf("接收到的字节数: %d\n", iResult);
		//接收缓存指针向后移动
		recvbuf +=iResult;
		//更新cnt值
		cnt -=iResult;         
	}
	return fixedlen;
}


int recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen)
{
	int iResult;//存储单次recvn操作的返回值
	unsigned int reclen; //用于存储报文头部存储的长度信息
	//获取接收报文长度信息
	iResult = recvn(s, ( char * )&reclen, sizeof( unsigned int ));
	if ( iResult !=sizeof ( unsigned int ) )
	{
		//如果长度字段在接收时没有返回一个整型数据就返回(连接关闭)或-1(发生错误)
		if ( iResult == -1 ) {
			printf("接收发生错误: %d\n", WSAGetLastError());
			return -1;
		}
		else {
			printf("连接关闭\n");
			return 0;
		}
	}
	//转换网络字节顺序到主机字节顺序
	reclen = ntohl( reclen );
	if ( reclen > recvbuflen )
	{
		printf("reclen>recvbuflen: %d>%d\n",reclen,recvbuflen);
		//如果recvbuf没有足够的空间存储变长消息,则接收该消息并丢弃,返回错误
		while ( reclen > 0){
			iResult = recvn( s, recvbuf, recvbuflen );
			if ( iResult != recvbuflen ) {
				//如果变长消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误)
				if ( iResult == -1 ) {
					printf("接收发生错误: %d\n", WSAGetLastError());
					return -1;
				}
				else {
					printf("连接关闭\n");
					return 0;
				}
			}
			reclen -= recvbuflen;
			//处理最后一段数据长度
			if ( reclen < recvbuflen )
				recvbuflen = reclen;
		}
		printf("可变长度的消息超出预分配的接收缓存\r\n");
		return -1;
	}
	//接收可变长消息
	iResult = recvn( s, recvbuf, reclen );
	if ( iResult != reclen )
	{
		//如果消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误)
		if ( iResult == -1 ) {
			printf("接收发生错误: %d\n", WSAGetLastError());
			return -1;
		}
		else {
			printf("连接关闭\n");
			return 0;
		}
	}
	return iResult;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值