服务端: BlockTcpServer
/**************************** begin ************************/
// BlockServer.app
// class : BlockTcpServer
// Init,Bind,Listen,Accept,Recv,Send....
#include <iostream>
#include <WINSOCK2.H>
#pragma comment(lib, "wsock32.lib")
using namespace std;
class BlockTcpServer{
enum{
SERVER_EXIT_OK = 0 , //服务器正常退出
SERVER_API_OK = 0 , //调用 Socket API 成功
SERVER_DLL_ERROR = 1 , //调用Windows sockets DLL失败
SERVER_API_ERROR = 2 , //调用 Socket API 失败
SERVERPORT = 5555, //定义服务器 TCP 端口
MAX_NUM_BUF = 64 , //缓冲区尺寸
SOCKET_VERSION = MAKEWORD(2,2)
};
private:
int InitMember(void); //初始化成员变量
int ExitClient(int nExit); //客户端退出
BOOL RecvLine(SOCKET s, char* buf); //读取一行数据
BOOL SendLine(SOCKET s, char* buf); //发送一行数据
int HandleSocketError(char *str); //对Windows sockets API调用错误处理
void ShowSocketMsg(char* str); //显示错误信息
public:
int ServerRun(void);
private:
char bufRecv[MAX_NUM_BUF]; //读缓冲区
char bufSend[MAX_NUM_BUF]; //写缓冲区
SOCKET sServer; //服务器监听套接字
SOCKET sClient; //接受客户端套接字
BOOL bConning; //与客户端的连接状态
};
/**************************/
int main(int argc, char* argv[])
{
BlockTcpServer bts;
while(1){
bts.ServerRun();
Sleep(50);
}
return 1;
}
/**************************/
int BlockTcpServer::ServerRun(void)
{
if(SERVER_API_OK != InitMember()){
ShowSocketMsg(" InitMember 失败 /n ");
return -1;
}
//创建套接字
sServer= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(INVALID_SOCKET == sServer)
{
return HandleSocketError("Failed socket()!");
}
//服务器套接字地址
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()!"); //错误处理
}
//开始监听
retVal = listen(sServer, 1);
if(SOCKET_ERROR == retVal)
{
closesocket(sServer); //关闭套接字
return HandleSocketError("Failed listen()!");//错误处理
}
//等待客户端的连接
cout << "Server succeeded!" << endl;
cout << "Waiting for new clients..." << endl;
//接受客户端请求
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);
cout<<"Accept a client."<<endl;
cout<<"IP: "<<pClientIP<<endl;
cout<<"Port: "<<clientPort<<endl;
//接收客户端数据
if (!RecvLine(sClient, bufRecv))
{
ShowSocketMsg(" RecvLine () 失败 .. /n");
return ExitClient(SERVER_API_ERROR);//退出
}
//显示客户端数据
cout << bufRecv<<endl;
//向客户端发送数据
strcpy(bufSend, "Hello,Client!/n");
if (!SendLine(sClient, bufSend))
{
ShowSocketMsg(" SendLine () 失败 .. /n");
return ExitClient(SERVER_API_ERROR);
}
//显示退出信息
cout << "Server exiting..." << endl;
//退出
return ExitClient(SERVER_EXIT_OK);
}
/*
* 初始化成员变量
*/
int BlockTcpServer::InitMember(void)
{
//初始化读和写缓冲区
memset(bufRecv, 0, MAX_NUM_BUF);
memset(bufSend, 0, MAX_NUM_BUF);
//初始化
sServer = INVALID_SOCKET;
sClient = INVALID_SOCKET;
//没有连接状态
bConning = FALSE;
WSADATA wsaData; //Windows sockets DLL版本信息
int retVal; //调用Windows sockets API返回值
//初始化Windows Sockets DLL
retVal = WSAStartup(SOCKET_VERSION, &wsaData);
if ( 0 != retVal )
{
ShowSocketMsg("Can not find a usable Windows Sockets dll!");
return SERVER_DLL_ERROR;
}
//确保WinSock DLL支持2.2
if ( LOBYTE( wsaData.wVersion ) != LOBYTE(SOCKET_VERSION) || HIBYTE( wsaData.wVersion ) != HIBYTE(SOCKET_VERSION) )
{
ShowSocketMsg("Can not find a usable Windows Sockets dll!");
WSACleanup( );
return SERVER_DLL_ERROR;
}
return SERVER_API_OK;
}
/*
* 退出
*/
int BlockTcpServer::ExitClient(int nExit)
{
closesocket(sServer); //关闭监听套接字
closesocket(sClient); //关闭连接客户端套接接
WSACleanup(); //卸载Windows sockets DLL 清理内存
return nExit; //退出
}
/*
* 读一行数据
*/
BOOL BlockTcpServer::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)
{
ShowSocketMsg("The socket is not connected!");
}else if(WSAESHUTDOWN == nErrCode)
{
ShowSocketMsg("The socket has been shut down!");
}else if (WSAETIMEDOUT == nErrCode)
{
ShowSocketMsg("The connection has been dropped!");
}else if (WSAECONNRESET == nErrCode)
{
ShowSocketMsg("The virtual circuit was reset by the remote side!");
}else{}
retVal = FALSE; //读数据失败
break; //跳出循环
}
if (0 == nReadLen)// ??
{
retVal = FALSE; //读数据失败
break ; //跳出循环
}
//读入数据
if ('/n' == *(buf + nDataLen)) //换行符
{
bLineEnd = TRUE; //接收数据结束
}else{
nDataLen += nReadLen; //增加数据长度
}
}
return retVal;
}
/*
* //发送一行数据
*/
BOOL BlockTcpServer::SendLine(SOCKET s, char* str)
{
int retVal;//返回值
retVal = send(s, str, strlen(str), 0);//一次发送
//错误处理
if (SOCKET_ERROR == retVal)
{
int nErrCode = WSAGetLastError();//错误代码
if (WSAENOTCONN == nErrCode)
{
ShowSocketMsg("The socket is not connected!");
}else if(WSAESHUTDOWN == nErrCode)
{
ShowSocketMsg("The socket has been shut down!");
}else if (WSAETIMEDOUT == nErrCode)
{
ShowSocketMsg("The connection has been dropped!");
}else{}
return FALSE; //发送失败
}
return TRUE; //发送成功
}
/*
* 错误处理
*/
int BlockTcpServer::HandleSocketError(char *str)
{
ShowSocketMsg(str); //显示错误消息
WSACleanup(); //卸载Windows socket DLL
return SERVER_API_ERROR;//退出应用程序
}
/*
* 显示错误
*/
void BlockTcpServer::ShowSocketMsg(char* str)
{
MessageBox(NULL, str, "SERVER ERROR", MB_OK);
}
/*************************** end ****************************/
客户端: BlockTcpClient
/**************************** begin ************************/
// Client.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <winsock.h>
#include <iostream>
#pragma comment(lib, "wsock32.lib")
using namespace std;
class BlockTcpClient{
enum{
CLIENT_EXIT_OK = 0 , //客户端正常退出
CLIENT_DLL_ERROR = 1 , //调用Windows socket dll失败
CLIENT_API_ERROR = 2 , //调用Windows socket api失败
CLIENT_API_OK = 0 ,
MAX_NUM_BUF = 64 , //缓冲区的最大长度
SERVERPORT = 5555 , //服务器TCP端口
SOCKET_VERSION = MAKEWORD(2,2)
};
private:
int InitMember(void); //初始化变量
int ExitClient(int nExit); //退出
BOOL RecvLine(SOCKET s, char* buf); //读取一行数据
void ShowErrorMsg(void); //显示错误信息
void ShowIpAndPort(SOCKADDR_IN & addr);
public:
BlockTcpClient(void);
~BlockTcpClient(void);
int ClientRun(void);
BOOL GetInit(void){ return Init; }
private:
char bufRecv[MAX_NUM_BUF]; //读缓冲区
char bufSend[MAX_NUM_BUF]; //写缓冲区
SOCKET sHost; //socket
BOOL bConning; //连接服务器状态
BOOL Init;
};
/************************************/
int main(){
BlockTcpClient btc;
if( !btc.GetInit() ) return -1;
while(1){
btc.ClientRun();
//Sleep(30);
}
return 0;
}
/************************************/
BlockTcpClient::BlockTcpClient(void){
Init = true;
if(CLIENT_API_OK != InitMember()){
//ShowSocketMsg(" InitMember 失败 /n ");
cout << "InitMember 失败 /n" << endl;
Init = false;
}
}
BlockTcpClient::~BlockTcpClient(void){
WSACleanup();
}
int BlockTcpClient::ClientRun(void)
{
//初始化变量
/*
if(CLIENT_API_OK != InitMember()){
//ShowSocketMsg(" InitMember 失败 /n ");
cout << "InitMember 失败 /n" << endl;
return -1;
}
*/
//创建Windows socket
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(INVALID_SOCKET == sHost)
{
ShowErrorMsg(); //显示错误信息
//WSACleanup(); //释放资源
return CLIENT_API_ERROR;//退出
}
//准备连接服务器
cout << "Client succeeded!" << endl;
cout<<"Be ready to connect to server..."<<endl;
//获取主机的信息 ???????????????
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);
cout << "Befor connect()." << endl;
ShowIpAndPort(addrServ);
//连接服务器
int retVal = connect(sHost,(LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
cout << "After connect()." << endl;
ShowIpAndPort(addrServ);
if(SOCKET_ERROR == retVal)
{
ShowErrorMsg(); //显示错误信息
return ExitClient(CLIENT_API_ERROR); //退出
}else{
bConning = TRUE; //连接服务器成功
}
//连接服务器成功
cout<<"Connect successfully!"<<endl;
//向服务器发送数据
strcpy(bufSend, "Hello, Server!/n");
retVal = send(sHost, bufSend, strlen(bufSend), 0);
if (SOCKET_ERROR == retVal)
{
ShowErrorMsg(); //显示错误信息
return ExitClient(CLIENT_API_ERROR); //退出
}
//从服务器接收数据
if (!RecvLine(sHost, bufRecv))
{
ShowErrorMsg(); //显示错误信息
return ExitClient(CLIENT_API_ERROR); //退出
}
//显示服务器的应答
cout<<bufRecv<<endl;
//退出
return ExitClient(CLIENT_EXIT_OK);
}
/*
* 显示错误信息
*/
void BlockTcpClient::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, (char*)LocalLock(hlocal), "CLIENT ERROR", MB_OK);
LocalFree(hlocal);
}
}
/*
* 初始化成员变量
*/
int BlockTcpClient::InitMember(void)
{
//初始化读和写缓冲区
memset(bufRecv, 0, MAX_NUM_BUF);
memset(bufSend, 0, MAX_NUM_BUF);
//初始化
sHost = INVALID_SOCKET;
//没有连接状态
bConning = FALSE;
WSADATA wsaData; //Windows sockets DLL版本信息
int retVal; //调用Windows sockets API返回值
//初始化Windows Sockets DLL
retVal = WSAStartup(SOCKET_VERSION, &wsaData);
if ( 0 != retVal )
{
cout << "Can not find a usable Windows Sockets dll!" << endl;
return CLIENT_DLL_ERROR;
}
//确保WinSock DLL支持2.2
if ( LOBYTE( wsaData.wVersion ) != LOBYTE(SOCKET_VERSION) || HIBYTE( wsaData.wVersion ) != HIBYTE(SOCKET_VERSION) )
{
cout << "Can not find a usable Windows Sockets dll!" << endl;
//WSACleanup( );
return CLIENT_DLL_ERROR;
}
return CLIENT_API_OK;
}
/*
* 退出
*/
int BlockTcpClient::ExitClient(int nExit)
{
closesocket(sHost); //关闭套接字
//WSACleanup(); //卸载Windows sockets DLL 清理内存
//显示退出信息
cout << "Client exiting..." << endl;
//Seep(50);
return nExit; //退出
}
/*
* 读取一行数据
*/
BOOL BlockTcpClient::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;
}
//显示 Socket 的 IP和端口 SOCKADDR_IN
void BlockTcpClient::ShowIpAndPort(SOCKADDR_IN & addr)
{
char *pIP = inet_ntoa(addr.sin_addr);
u_short sPort = ntohs(addr.sin_port);
cout<<"IP and Port :"<<endl;
cout<<"IP: "<<pIP<<endl;
cout<<"Port: "<<sPort<<endl;
}
// struct hostent {
// char FAR * h_name;
// char FAR * FAR * h_aliases;
// short h_addrtype;
// short h_length;
// char FAR * FAR * h_addr_list;
// };