阻塞模式 客户端与服务器相互问候 TCP/IP通信 63页

  1. 代码来源于 》》》》》》》》》》》》》》》》》》》》》 Windows Sockets网络开发VC++ 这本书  

  1. 在stdafx.h 中添加 #pragma comment(lib,"ws2_32.lib")  


服务器实现

// ServerCSgreeting.cpp : 客户端与服务器相互问候。
//

#include "stdafx.h"
#include "winsock2.h"
#include "funtiondec.h"   //所需函数声明
#include "string.h"

#define MAX_NUM_BUF 20  //需要读入数据的大小
#define SERVER_DLL_REEOR 1 //调用Windows sockets DLL失败
#define SERVER_API_ERROR 2 //调用socket DLL失败
#define SERVERPORT 5555   // 服务器TCP端口
//#define INVALID_SOCKET (SOCKET)(~0)
//#define SOCKET_ERROR    (-1)


char bufRecv[MAX_NUM_BUF]; //读缓冲区
char  bufSend[MAX_NUM_BUF]; //写缓冲区
SOCKET sServer;  //服务器监听套接字
SOCKET sClient;  //接受客户端套接字
bool bConning;   //与客户端的连接状态变量


/*
	初始化成员变量
*/
void InitMember(void)
{
	//初始化读和写缓冲区
	memset(bufRecv, 0, MAX_NUM_BUF);
	memset(bufSend, 0, MAX_NUM_BUF);

	//初始化
	sServer = INVALID_SOCKET;
	sClient = INVALID_SOCKET;

	//没有连接状态
	bConning = FALSE;
}

/*
	Windows Sockets 动态库的初始化
*/
int InitWinSoDll(void)
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(1, 1);
	int retVal = WSAStartup(wVersionRequested, &wsaData);

	if (0 != retVal)
	{
		printf("Can not find a usable Windows Sockets dll!");
		return SERVER_DLL_REEOR;
	}

	//确保WinSock DLL 支持1.1
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		printf("Can not find a usable Windows Sockets dll!");
		WSACleanup();
		return SERVER_DLL_REEOR;
	}

	return 0;
}

/*
	创建套接字
*/
int CreateSocket(void)
{
	sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sServer)
	{
		return HandleSocketError("Failed socket()!");
	}

	return 0;
}

/*
	错误处理
*/
int HandleSocketError(char *str)
{
	printf("%s", str);
	WSACleanup();

	return SERVER_API_ERROR;
}

/*
	绑定套接字
*/
int BindSoc(void)
{
	//服务器套接字地址
	SOCKADDR_IN addrServ;
	addrServ.sin_family = AF_INET;
	addrServ.sin_port = htons(SERVERPORT);
	addrServ.sin_addr.s_addr = INADDR_ANY;
	

	//绑定套接字
	int retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
	if (SOCKET_ERROR == retVal)
	{
		closesocket(sServer);  //关闭套接字
		return HandleSocketError("Failed bind()!");  //错误处理
	}

	return 0;
}

/*
	监听
*/
int ListenSoc(void)
{
	//开始监听
	int retVal = listen(sServer, 1);
	if (SOCKET_ERROR == retVal)
	{
		closesocket(sServer);
		return HandleSocketError("Failed listen()!");
	}

	//等待客户端的连接
	printf("Server succeeded!\n");
	printf("Waiting for new clients...\n");
	return 0;
}

/*
	接受请求
*/
int AcceptSoc(void)
{
	//接受客户端请求
	sockaddr_in addrClient;
	int addrClientlen = sizeof(addrClient);

	sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);
	if (INVALID_SOCKET == sClient)
	{
		closesocket(sServer);
		return HandleSocketError("Failed accept()!");
	}else
	{
		bConning = TRUE;  //客户端请求成功
	}

	//显示客户端的IP和端口
	char *pClientIP = inet_ntoa(addrClient.sin_addr);
	u_short clientPort = ntohs(addrClient.sin_port);
	printf("Accept a client.\n");
	printf("IP:%s\n", pClientIP);
	printf("Port:%d\n", clientPort);

	return 0;
}

/*
	接收数据
*/
BOOL RecvLine(SOCKET s, char* buf)
{
	BOOL retVal = TRUE;  //返回值
	BOOL bLineEnd = FALSE;  //行结束
	int nReadLen = 0;  //读入字节数
	int nDataLen = 0;  //数据长度
	while (!bLineEnd && bConning)  //与客户端连接 没有换行
	{
		nReadLen = recv(s, buf + nDataLen, 1, 0); // 每次接收一个字节

		//错误处理
		if (SOCKET_ERROR == nReadLen)
		{
			int nErrCode = WSAGetLastError();  //错误代码
			if (WSAENOTCONN == nErrCode)
			{
				printf("The socket is not conected!\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{}

			retVal = FALSE;// 读取数据失败
			break;
		}

		if (0 == nReadLen) //客户端关闭
		{
			retVal = FALSE;  //读取数据失败
			break;
		}

		//读入数据
		if ('\n' == *(buf + nDataLen))
		{
			bLineEnd = TRUE;  //接收数据结束
		}
		else
		{
			nDataLen += nReadLen;  //增加数据掺毒
		}
	}

	return retVal;
}

/*
	发送一行数据
*/
BOOL SendLine(SOCKET s, char* str)
{
	int retVal;  //返回值
	retVal = send(s, str, strlen(str), 0);  //一次发送

	//错误处理
	if (SOCKET_ERROR == retVal)
	{
		int nErrCode = WSAGetLastError();
		if (WSAENOTCONN == nErrCode)
		{
			printf("The socket is not conected!");
		}
		else if (WSAESHUTDOWN == nErrCode)
		{
			printf("The socket has been shut down!");
		}
		else if (WSAETIMEDOUT == nErrCode)
		{
			printf("The connection has been dropped!");
		}
		else{}

		return FALSE;  //发送失败
	}
	return TRUE;  //发送成功
}

/*
	退出
*/
int ExitClient(int nExit)
{
	closesocket(sServer);  //关闭监听套接字
	closesocket(sClient);  //关闭连接客户端套接字
	WSACleanup();  //卸载Windows Sockets DLL清理内存
	return nExit; //退出
}

int _tmain(int argc, _TCHAR* argv[])
{
	char bufSend[MAX_NUM_BUF] = { NULL };
	char bufRecv[MAX_NUM_BUF] = { NULL };

	strcpy_s(bufSend, "Hello,Client!\n");

	InitMember(); // 初始化成员
	InitWinSoDll();  //初始化Windows Sockets DLL

	CreateSocket();  //创建套接字
	BindSoc();      //绑定套接字
	ListenSoc();  //监听
	AcceptSoc();  //接受客户端请求


	if (!RecvLine(sClient, bufRecv)) //接收数据
	{
		return HandleSocketError("RecvLine Error!\n");
	}
	printf("RecvLine=%s\n", bufRecv);

	printf("RecvLine succeeded!\n");
	if (!SendLine(sClient, bufSend))//发送一行数据
	{
		return ExitClient(SERVER_API_ERROR);
	}

	ExitClient(0);

	return 0;
}



客户端实现

// ClientCSgreeting.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "winsock2.h"
#include "funtiondec.h"
#include "string.h"

#define MAX_NUM_BUF 25  //需要读写入数据的大小
#define CLIENT_SOCKET_DLL_ERROR 1 //调用Windows sockets DLL失败
#define CLIENT_API_ERROR 2   //创建套接字失败
#define SERVERPORT 5555   // 服务器TCP端口

char bufRecv[MAX_NUM_BUF]; //读缓冲区
char bufSend[MAX_NUM_BUF]; //写缓冲区
SOCKET sHost; //套接字
bool bConning;   //与服务器的连接状态变量

/*
初始化成员变量
*/
void InitMember(void)
{
	//初始化读和写缓冲区
	memset(bufRecv, 0, MAX_NUM_BUF);
	memset(bufSend, 0, MAX_NUM_BUF);

	//初始化
	sHost = INVALID_SOCKET;

	//没有连接状态
	bConning = FALSE;
}

/*
Windows Sockets 动态库的初始化
*/
int InitWinSoDll(void)
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(1, 1);
	int err = WSAStartup(wVersionRequested, (LPWSADATA)&wsaData);

	if (0 != err)
	{
		printf("Can not find a usable Windows Sockets dll!");
		return CLIENT_SOCKET_DLL_ERROR;
	}


	return 0;
}

/*
创建套接字
*/
int CreateSocket(void)
{
	//创建Windows socket
	sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sHost)
	{
		ShowErrorMsg();  //显示错误信息
		WSACleanup(); //释放资源
		return CLIENT_API_ERROR;  //退出
	}

	return 0;
}

/*
	显示错误信息
*/
void ShowErrorMsg(void)
{
	int nErrCode = WSAGetLastError(); //获取错误代码
	HLOCAL hlocal = NULL;

	//获取错误的文本字符串
	BOOL fok = FormatMessage(
		FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
		NULL, nErrCode, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
		(PTSTR)&hlocal, 0, NULL
		);

	//显示错误信息
	if (hlocal != NULL)
	{
		MessageBox(NULL, (LPCWSTR)LocalLock(hlocal), _T("CLIENT ERROR"), MB_OK);
		LocalFree(hlocal);
	}
}

/*
	客户端连接服务器
*/
int ConnectSoc(void)
{
	//获取主机的信息
	int retVal;
	LPHOSTENT hostEntry;
	char hostname[MAX_NUM_BUF];
	gethostname(hostname, MAX_NUM_BUF);  //获取主机名称
	hostEntry = gethostbyname(hostname);  //获取主机信息
	
	if (!hostEntry)
	{
		ShowErrorMsg();   //显示错误信息
		return ExitClient(CLIENT_API_ERROR); //退出
	}

	//设置sockaddr_in
	SOCKADDR_IN addrServ;
	addrServ.sin_family = AF_INET;
	addrServ.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
	addrServ.sin_port = htons(SERVERPORT);

	char *pClientIP = inet_ntoa(addrServ.sin_addr);
	printf("IP:%s\n", pClientIP);

	//连接服务器
	retVal = connect(sHost, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
	if (SOCKET_ERROR == retVal)
	{
		ShowErrorMsg();   //显示错误信息
		return ExitClient(CLIENT_API_ERROR);  //退出
	}
	else
	{
		bConning = TRUE;  //连接服务器成功
		printf("Connect succeedend!\n");
	}
	return 0;
}

/*
	发送数据
*/
int SendData(char *str)
{
	
	int retVal = send(sHost, str, strlen(str), 0);

	if (SOCKET_ERROR == retVal)
	{
		ShowErrorMsg();  //显示错误信息
		return ExitClient(CLIENT_API_ERROR); //退出
	}
	return 0;
}

/*
	读取一行数据
*/
BOOL RecvLine(SOCKET s, char* buf)
{
	BOOL retVal = TRUE;  //返回值
	BOOL bLineEnd = FALSE;  //行结束
	int nReadLen = 0;  //读入字节数
	int nDataLen = 0;  //数据长度
	while (!bLineEnd && bConning)
	{
		nReadLen = recv(s, buf + nDataLen, 1, 0); //每次接收一个字节

		//错误处理
		if (SOCKET_ERROR == nReadLen)
		{
			retVal = FALSE;  //读数据失败
			break;  // 跳出循环
		}

		if (0 == nReadLen)  //客户端关闭
		{
			retVal = FALSE;  //读数据失败
			break; 
		}

		//读入数据
		if ('\n' == *(buf + nDataLen))  //换行符
		{
			bLineEnd = TRUE;  //接收数据结束
		}
		else
		{
			nDataLen += nReadLen;  //增加数据长度
		}
	}

	return retVal;
}

/*
	退出
*/
int ExitClient(int nExit)
{
	closesocket(sHost);  //关闭连接服务器套接字
	WSACleanup();  //卸载Windows Sockets DLL清理内存
	return nExit; //退出
}

int _tmain(int argc, _TCHAR* argv[])
{
	char recvbuf[MAX_NUM_BUF] = { NULL };
	char bufSend[MAX_NUM_BUF] = { NULL };

	strcpy_s(bufSend, "Hello,Server!\n");

	InitMember();  // 初始化成员
	InitWinSoDll();   //初始化Windows Sockets DLL

	CreateSocket();  //创建套接字
	ConnectSoc();   //客户端连接套接字

	if (SendData(bufSend) > 0)  //向服务器发送数据
	{
		printf("ClientSend Error\n");
		ExitClient(1);
	}
	else
	{
		printf("ClientSend succeeded\n");
		
	}


	if (RecvLine(sHost, recvbuf))  //读取一行数据
	{
		printf("ClientRecvLine=%s\n", recvbuf);
		printf("RecvLine succeeded!\n");
	}
	
	
	

	ExitClient(1);

	return 0;
}

 

效果图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值