服务器端:
// Server.cpp : Defines the entry point for the console application. // #include "stdio.h" #include <iostream> using namespace std; #include <sstream> #include <string> #include <WINSOCK2.H> #pragma comment(lib, "wsock32.lib") #define SERVER_EXIT_OK 0 //服务器正常退出 #define SERVER_DLL_REEOR 1 //调用Windows sockets DLL失败 #define SERVER_API_ERROR 2 //调用Windows sockets API失败 #define SERVERPORT 5555//服务器TCP端口 #define MAX_NUM_BUF 64 //缓冲区最大尺寸 //变量 char bufRecv[MAX_NUM_BUF]; //读缓冲区 char bufSend[MAX_NUM_BUF]; //写缓冲区 SOCKET sServer; //服务器监听套接字 SOCKET sClient; //接受客户端套接字 BOOL bConning; //与客户端的连接状态 //函数 void 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); //显示错误信息 //主函数 int main(int argc, char* argv[]) { InitMember(); //初始化变量 WORD wVersionRequested; //应用程序需要Windows sockets DLL的版本 WSADATA wsaData; //Windows sockets DLL版本信息 int retVal; //调用Windows sockets API返回值 //初始化Windows Sockets DLL wVersionRequested = MAKEWORD(1,1);//makeword是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a) retVal = WSAStartup(wVersionRequested, &wsaData);//Windows异步套接字的启动命令 //{1}一个WORD(双字节)型数值,指定了应用程序需要使用的Winsock规范的最高版本。 //{2}指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节。 if ( 0 != retVal ) { ShowSocketMsg("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) { ShowSocketMsg("Can not find a usable Windows Sockets dll!"); WSACleanup( );//中止Windows Sockets在所有线程上的操作. return SERVER_DLL_REEOR; } //创建套接字 sServer= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /*SOCKET PASCAL FAR socket( int af, int type, int protocol); af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。 type:新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。 protocol:套接口所用的协议。如调用者不想指定,可用0。 若无错误发生,socket()返回引用新套接口的描述字。否则的话,返回INVALID_SOCKET错误*/ 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; /*sin_family指代协议族,在socket编程中只能是AF_INET sin_port存储端口号(使用网络字节顺序) sin_addr存储IP地址,使用in_addr这个数据结构*/ //绑定套接字 retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN)); /*返回:成功返回0,失败返回-1. 参数列表中,sockfd 表示已经建立的)socket编号(描述符); my_addr 是一个指向sockaddr结构体类型的指针; 参数addrlen表示my_addr结构的长度,可以用sizeof函数获得。*/ if(SOCKET_ERROR == retVal) { closesocket(sServer); //关闭套接字 return HandleSocketError("Failed bind()!"); //错误处理 } int count=0; while(1){ //开始监听 retVal = listen(sServer, 2); /*S:用于标识一个已捆绑未连接套接口的描述字。 backlog:等待连接队列的最大长度*/ 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); /*s:套接口描述字,该套接口在listen()后监听连接。 addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。 addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。 */ if(INVALID_SOCKET == sClient) { closesocket(sServer); //关闭套接字 return HandleSocketError("Failed accept()!"); //错误处理 }else{ bConning = TRUE; //客户端请求成功 } //显示客户端的IP和端口 char *pClientIP = inet_ntoa(addrClient.sin_addr);//如果正确,返回一个字符指针,指向一块存储着点分格式IP地址的静态缓冲区 u_short clientPort = ntohs(addrClient.sin_port); //将一个无符号短整形数从网络字节顺序转换为主机字节顺序 cout<<"Accept a client."<<endl; cout<<"IP: "<<pClientIP<<endl; cout<<"Port: "<<clientPort<<endl; //接收客户端数据 if (!RecvLine(sClient, bufRecv)) { cout<<"接收数据失败!\n"; return ExitClient(SERVER_API_ERROR);//退出 } //显示客户端数据 cout << bufRecv<<endl; char temp[MAX_NUM_BUF]; int i=0; while(bufRecv[i]!=‘\n‘) { temp[i]=bufRecv[i]; i++; } temp[i]=‘\0‘; //向客户端发送数据 stringstream ss; string s(temp); count++; ss<<count; string str=""; str+=s; str+="你好!你是访问我服务的第"; str+=ss.str(); str+="个客户\n"; strcpy(bufSend, str.c_str()); if (!SendLine(sClient, bufSend)) { cout<<"发送失败!\n"; //return ExitClient(SERVER_API_ERROR); } } //显示退出信息 cout << "Server exiting..." << endl; //退出 return ExitClient(SERVER_EXIT_OK); } /* * 初始化成员变量 */ void InitMember(void) { //初始化读和写缓冲区 memset(bufRecv, 0, MAX_NUM_BUF); memset(bufSend, 0, MAX_NUM_BUF); //初始化 sServer = INVALID_SOCKET; sClient = INVALID_SOCKET; //没有连接状态 bConning = FALSE; } /* * 退出 */ int ExitClient(int nExit) { closesocket(sServer); //关闭监听套接字 closesocket(sClient); //关闭连接客户端套接接 WSACleanup(); //卸载Windows sockets DLL 清理内存 return nExit; //退出 } /* * 读一行数据 */ 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);//每次接收一个字节 /*s:一个标识已连接套接口的描述字。 buf:用于接收数据的缓冲区。 len:缓冲区长度。 flags:指定调用方式。*/ //错误处理 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 SendLine(SOCKET s, char* str) { int retVal;//返回值 retVal = send(s, str, strlen(str), 0);//一次发送 /*s:一个用于标识已连接套接口的描述字。 buf:包含待发送数据的缓冲区。 len:缓冲区中数据的长度。 flags:调用执行方式。*/ //错误处理 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 HandleSocketError(char *str) { ShowSocketMsg(str); //显示错误消息 WSACleanup(); //卸载Windows socket DLL return SERVER_API_ERROR;//退出应用程序 } /* * 显示错误 */ void ShowSocketMsg(char* str) { cout<<str; //MessageBox(NULL, str, "SERVER ERROR", MB_OK); }
客户端:
// Client.cpp : Defines the entry point for the console application. // #include "stdio.h" #include <windows.h> #include <winsock.h> #include <iostream> using namespace std; #pragma comment(lib, "wsock32.lib") #define CLIENT_EXIT_OK 0 //客户端正常退出 #define CLIENT_DLL_REEOR 1 //调用Windows socket dll失败 #define CLIENT_API_ERROR 2 //调用Windows socket api失败 #define MAX_NUM_BUF 64 //缓冲区的最大长度 #define SERVERPORT 5555//服务器TCP端口 //变量 char bufRecv[MAX_NUM_BUF]; //读缓冲区 char bufSend[MAX_NUM_BUF]; //写缓冲区 SOCKET sHost; //socket BOOL bConning; //连接服务器状态 //函数 void InitMember(void); //初始化变量 int ExitClient(int nExit); //退出 BOOL RecvLine(SOCKET s, char* buf); //读取一行数据 void ShowErrorMsg(void); //显示错误信息 //主函数 int main() { //初始化变量 InitMember(); WORD wVersionRequested; //应用程序需要Windows sockets DLL的版本 WSADATA wsaData; //Windows sockets DLL版本信息 int retVal; //调用Windows sockets API返回值 //初始化Windows Sockets DLL wVersionRequested = MAKEWORD(1,1); retVal = WSAStartup(wVersionRequested,(LPWSADATA)&wsaData); if ( 0 != retVal ) { cout<<"Error"; //MessageBox(NULL, "Can not find a usable Windows Sockets dll!", "ERROR", MB_OK); return CLIENT_DLL_REEOR; } //while(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_addr.s_addr = inet_addr("10.20.255.183"); addrServ.sin_port = htons(SERVERPORT); //连接服务器 retVal=connect(sHost,(LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN)); if(SOCKET_ERROR == retVal) { ShowErrorMsg(); //显示错误信息 return ExitClient(CLIENT_API_ERROR); //退出 }else{ bConning = TRUE; //连接服务器成功 } //连接服务器成功 cout<<"Connect successfully!"<<endl; //向服务器发送数据 int i=0; char c; char s[MAX_NUM_BUF]; cout<<"输入您的姓名:\n"; while((c=getchar())!=‘\n‘) { s[i++]=c; } s[i++]=‘\n‘; s[i]=‘\0‘; strcpy(bufSend, s); 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; //Sleep(2000); //退出 return ExitClient(CLIENT_EXIT_OK); } /* * 显示错误信息 */ 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) { cout<<LocalLock(hlocal); //MessageBox(NULL, (char*)LocalLock(hlocal), "CLIENT ERROR", MB_OK); LocalFree(hlocal); } } /* * 初始化成员变量 */ void InitMember(void) { //初始化读和写缓冲区 memset(bufRecv, 0, MAX_NUM_BUF); memset(bufSend, 0, MAX_NUM_BUF); //初始化 sHost = INVALID_SOCKET; //没有连接状态 bConning = FALSE; } /* * 退出 */ int ExitClient(int nExit) { closesocket(sHost); //关闭套接字 WSACleanup(); //卸载Windows sockets DLL 清理内存 //显示退出信息 cout << "Client exiting..." << endl; Sleep(5000); return nExit; //退出 } /* * 读取一行数据 */ 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; }
服务器端:
客户端:
原文:http://blog.csdn.net/starcuan/article/details/21107449