这是我编写的第二个回射程序。程序大体是这样的:
客户端的编写上一篇给出的客户端的编写方法是一样的,同样用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;
}