回射程序2(服务器)——服务器接收定长数据

本文介绍了一个回射程序的服务器部分,重点在于如何通过自定义的recvn函数接收固定长度的数据。客户端发送一个unsigned int变量,经过字节序转换后发送到服务器,服务器使用recvn函数接收到sizeof(unsigned int)长度的数据。htonl和ntohl等字节序转换函数在编程中至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是我编写的第二个回射程序。程序大体是这样的:


客户端的编写上一篇给出的客户端的编写方法是一样的,同样用recvline方法接收一行数据。这里不再赘述。

在服务器的编写上,这里不再像前面使用常规的recv方法接收数据,而是自己定义一个函数recvn,用于接收固定长度的数据,其中固定长度由运行程序指定。

这里实现的内容很简单,在客户端创建一个unsigned int类型的变量,发送到服务器端,服务器端使用recvn接收长度为sizeof(unsigned int)的数据,作为接收固定长度数据的体现。

PS:值得注意的是,在发送unsigned int类型的数据时,需要进行字节序的转换。htonl、ntohl等等一定要搞明白!!!

下面贴代码:

// 回显服务器2.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);
BOOL recvline(SOCKET S,char* buf);

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;//连接套接字
	unsigned int recvdata; //用于接收发送过来的数字
	char sendbuf[MAXSIZE];//发送缓存
	sServer = accept(slisten,(struct sockaddr*)&clientaddr,&clientaddrlen);
	if(sServer == INVALID_SOCKET)
	{
		printf("accept() failed!code:%d\n",WSAGetLastError());
		closesocket(slisten);
		WSACleanup();
		return -1;
	}
	//memset(buff,0,MAXSIZE);
	memset(sendbuf,0,MAXSIZE);
	while(TRUE)  //循环接收数据
	{
		ret = recvn(sServer,(char*)&recvdata,sizeof(unsigned int));
		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;
		}
		recvdata = ntohl(recvdata);
		sprintf(sendbuf,"echo:%d\n",recvdata);
		printf("%s\n",sendbuf);
		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;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值