windows套接字阻塞模式编程实例
一、阻塞模式套接字服务端和客户端的运行流程如下:
1.1 服务器运行过程如下:
1.服务器启动后,等待客户端的连接请求。
2.当收到客户端的请求后,在界面上显示该客户端的IP地址和端口,以及“Hello,Server!”问候语。
3.服务器向该客户端应答“Hello,Clinet!”问候语。
4.服务器退出。
1.2客户端运行过程如下:
1.客户端启动后,向服务器发起连接请求。
2.当连接请求被接受后,客户端向服务器发送“Hello,Server!”问候语。
3.等待服务器的应答。
4.当客户端收到服务器的“Hello,Clinet!”应答后,客户端退出。
1.3 客户端和服务器端工作流程如下:
二、实例
2.1 服务器端:Server.cpp
1 #include<iostream> 2 #include<winsock2.h> 3 #include<string> 4 #pragma comment(lib,"ws2_32.lib") 5 using namespace std; 6 7 #define SERVER_EXIT_OK 0 8 #define SERVER_DLL_ERROR 1 9 #define SERVER_API_ERROR 2 10 #define SERVERPORT 8888 11 #define MAX_NUM_BUF 64 12 13 //全局变量 14 char bufRecv[MAX_NUM_BUF];//读缓冲区 15 char bufSend[MAX_NUM_BUF];//写缓冲区 16 SOCKET sServer;//服务器监听套接字 17 SOCKET sClient;//接受客户端套接字 18 bool bConning;//与客户端的连接状态变量 19 20 //函数 21 void InitMember(void); 22 void ShowSocketMsg(char* str); 23 int HandleSocketError(char* str); 24 BOOL RecvLine(SOCKET s, char *buf);//读取一行数据 25 BOOL SendLine(SOCKET s,char * buf);//发送一行数据 26 int ExitClient(int nExit);//退出程序 27 28 int main(int argc,char*argv[]) 29 { 30 //调用初始化函数,进行相关初始化工作 31 InitMember(); 32 //Windows Sockets动态库初始化 33 WORD wVersionRequseted; 34 WSADATA wsaData; 35 int retVal; 36 wVersionRequseted = MAKEWORD(2,2); 37 retVal = WSAStartup(wVersionRequseted,&wsaData); 38 if (retVal!=0) 39 { 40 ShowSocketMsg("初始化动态连接库失败"); 41 return SERVER_DLL_ERROR; 42 } 43 //确保Winsock dll支持2.2 44 if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion!=2)) 45 { 46 ShowSocketMsg("没有发现动态链接库"); 47 return SERVER_DLL_ERROR; 48 } 49 //创建套接字 50 sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 51 if (INVALID_SOCKET==sServer) 52 { 53 return HandleSocketError("Faild socket()!"); 54 } 55 //服务器套接字地址 56 SOCKADDR_IN addrServer; 57 addrServer.sin_family = AF_INET; 58 addrServer.sin_port = htons(SERVERPORT); 59 addrServer.sin_addr.S_un.S_addr = INADDR_ANY; 60 //绑定套接字 61 retVal = bind(sServer,(sockaddr*)&addrServer,sizeof(addrServer)); 62 if (SOCKET_ERROR==retVal) 63 { 64 closesocket(sServer); 65 return HandleSocketError("绑定套接字失败"); 66 } 67 //监听 68 retVal = listen(sServer,5); 69 if (SOCKET_ERROR==retVal) 70 { 71 closesocket(sServer); 72 return HandleSocketError("监听失败"); 73 } 74 cout << "服务器开始初始化成功!" << endl; 75 cout << "等待客户端的连接...." << endl; 76 //接受客户端的请求 77 sockaddr_in addrClient; 78 int addrClientLen = sizeof(addrClient); 79 sClient = accept(sServer,(sockaddr*)&addrClient,&addrClientLen); 80 if (SOCKET_ERROR==sClient) 81 { 82 closesocket(sServer); 83 return HandleSocketError("接受客户端请求失败"); 84 } 85 //显示客户端的IP和端口 86 char *pClientIP = inet_ntoa(addrClient.sin_addr); 87 u_short clientPort = ntohs(addrClient.sin_port); 88 cout << "接受到来自客户端的请求:" << endl; 89 cout << "客户端的IP:" << pClientIP << endl; 90 cout << "客户端的端口:" << clientPort << endl; 91 //接受客户端的数据 92 if (!RecvLine(sClient,bufRecv)) 93 { 94 return ExitClient(SERVER_API_ERROR); 95 } 96 //显示客户端的数据 97 cout << bufRecv << endl; 98 //向客户端发送数据 99 strcpy(bufSend,"hello,client!\n"); 100 if (!SendLine(sClient,bufSend)) 101 { 102 return ExitClient(SERVER_API_ERROR); 103 } 104 //显示退出信息 105 cout << "服务器正在退出>>>>>" << endl; 106 //退出 107 return ExitClient(SERVER_EXIT_OK); 108 getchar(); 109 return 0; 110 } 111 112 113 //初始化成员变量 114 void InitMember(void) 115 { 116 //初始化缓冲区 117 memset(bufRecv, 0, MAX_NUM_BUF); 118 memset(bufSend, 0, MAX_NUM_BUF); 119 //初始化 120 sServer = INVALID_SOCKET; 121 sClient = INVALID_SOCKET; 122 //无连接状态 123 bConning = FALSE; 124 125 } 126 void ShowSocketMsg(char* str) 127 { 128 MessageBox(NULL,(LPCWSTR)str,(LPCWSTR)"SERVER_ERROR",MB_OK); 129 } 130 131 int HandleSocketError(char * str) 132 { 133 ShowSocketMsg(str);//显示错误 134 WSACleanup();//卸载Windows socket DLL 135 return SERVER_API_ERROR;//退出应用程序 136 } 137 138 BOOL RecvLine(SOCKET s, char * buf) 139 { 140 BOOL retVal=TRUE; //返回值 141 BOOL bLineEnd = FALSE; //行结束 142 int nReadLen = 0; //读入字节数 143 int nDataLen = 0; //数据长度 144 while (!bLineEnd&&bConning) //与客户端连接,没有换行 145 { 146 nReadLen = recv(s,buf+nDataLen,1,0); 147 //错误处理 148 if (SOCKET_ERROR==nReadLen) 149 { 150 int nErrorCode = WSAGetLastError(); 151 if (WSAENOTCONN==nErrorCode) 152 { 153 ShowSocketMsg("套接字未连接"); 154 } 155 else if (WSAESHUTDOWN==nErrorCode) 156 { 157 ShowSocketMsg("套接字已经关闭"); 158 } 159 else if (WSAETIMEDOUT == nErrorCode) 160 { 161 ShowSocketMsg("连接已断开!"); 162 } 163 else if (WSAECONNRESET == nErrorCode) 164 { 165 ShowSocketMsg("一个现存的远程主机上运行的客户端被强制关闭!"); 166 } 167 else {} 168 169 retVal = FALSE; //读数据失败 170 break; 171 } 172 173 if (nReadLen==0)//客户端关闭 174 { 175 retVal = FALSE; 176 break; 177 } 178 //读入数据 179 if (*(buf+nDataLen)=='\n') 180 { 181 bLineEnd = TRUE;//接受数据结束 182 } 183 else 184 { 185 nDataLen += nReadLen;//增加数据长度 186 } 187 } 188 189 return retVal; 190 } 191 192 BOOL SendLine(SOCKET s, char * buf) 193 { 194 int retVal=0;//返回值 195 retVal = send(s, buf, strlen(buf), 0);//一次发送 196 //错误处理 197 if (SOCKET_ERROR == retVal) 198 { 199 int nErrCode = WSAGetLastError();//错误代码 200 if (WSAENOTCONN == nErrCode) 201 { 202 ShowSocketMsg("套接字未连接"); 203 204 } 205 else if (WSAESHUTDOWN == nErrCode) 206 { 207 ShowSocketMsg("套接字已关闭!"); 208 209 } 210 else if (WSAETIMEDOUT == nErrCode) 211 { 212 ShowSocketMsg("连接已断开!"); 213 } 214 else {} 215 216 return FALSE; //发送失败 217 } 218 219 return TRUE; 220 } 221 222 int ExitClient(int nExit) 223 { 224 closesocket(sServer); //关闭监听套接字 225 closesocket(sClient); //关闭连接客户端套接接 226 WSACleanup(); //卸载Windows sockets DLL 清理内存 227 return nExit; //退出 228 }
2.2 客户端:Client.cpp
1 #include <windows.h> 2 #include <winsock.h> 3 #include <iostream> 4 #pragma comment(lib, "wsock32.lib") 5 using namespace std; 6 7 8 #define CLIENT_EXIT_OK 0 //客户端正常退出 9 #define CLIENT_DLL_REEOR 1 //调用Windows socket dll失败 10 #define CLIENT_API_ERROR 2 //调用Windows socket api失败 11 #define MAX_NUM_BUF 64 //缓冲区的最大长度 12 #define SERVERPORT 8888//服务器TCP端口 13 14 15 //变量 16 char bufRecv[MAX_NUM_BUF]; //读缓冲区 17 char bufSend[MAX_NUM_BUF]; //写缓冲区 18 SOCKET sHost; //socket 19 BOOL bConning; //连接服务器状态 20 21 //函数 22 void InitMember(void); //初始化变量 23 int ExitClient(int nExit); //退出 24 BOOL RecvLine(SOCKET s, char* buf); //读取一行数据 25 void ShowErrorMsg(void); //显示错误信息 26 27 //主函数 28 int main() 29 { 30 31 //初始化变量 32 InitMember(); 33 34 WORD wVersionRequested; //应用程序需要Windows sockets DLL的版本 35 WSADATA wsaData; //Windows sockets DLL版本信息 36 int retVal=0; //调用Windows sockets API返回值 37 38 //初始化Windows Sockets DLL 39 wVersionRequested = MAKEWORD(2, 2); 40 retVal = WSAStartup(wVersionRequested, (LPWSADATA)&wsaData); 41 if (0 != retVal) 42 { 43 MessageBox(NULL, (LPCWSTR)"初始化动态链接库失败!",(LPCWSTR) "ERROR", MB_OK); 44 return CLIENT_DLL_REEOR; 45 } 46 47 48 //创建Windows socket 49 sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 50 if (INVALID_SOCKET == sHost) 51 { 52 ShowErrorMsg(); //显示错误信息 53 WSACleanup(); //释放资源 54 return CLIENT_API_ERROR;//退出 55 } 56 57 //准备连接服务器 58 cout << "客户端初始化成功!" << endl; 59 cout << "准备连接到服务器..." << endl; 60 61 62 63 //获取主机的信息 64 LPHOSTENT hostEntry; 65 char hostname[MAX_NUM_BUF]; 66 gethostname(hostname, MAX_NUM_BUF); //获取主机名称 67 hostEntry = gethostbyname(hostname); //获取主机信息 68 if (!hostEntry) 69 { 70 ShowErrorMsg(); //显示错误信息 71 return ExitClient(CLIENT_API_ERROR); //退出 72 } 73 //设置sockaddr_in 74 SOCKADDR_IN addrServ; 75 addrServ.sin_family = AF_INET; 76 addrServ.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list); 77 addrServ.sin_port = htons(SERVERPORT); 78 //连接服务器 79 retVal = connect(sHost, (sockaddr*)&addrServ, sizeof(addrServ)); 80 if (SOCKET_ERROR == retVal) 81 { 82 ShowErrorMsg(); //显示错误信息 83 return ExitClient(CLIENT_API_ERROR); //退出 84 } 85 else { 86 bConning = TRUE; //连接服务器成功 87 } 88 //连接服务器成功 89 cout << "连接服务器成功!" << endl; 90 91 92 //向服务器发送数据 93 strcpy_s(bufSend, "Hello,Server!\n"); 94 retVal = send(sHost, bufSend, strlen(bufSend), 0); 95 if (SOCKET_ERROR == retVal) 96 { 97 ShowErrorMsg(); //显示错误信息 98 return ExitClient(CLIENT_API_ERROR); //退出 99 } 100 101 //从服务器接收数据 102 if (!RecvLine(sHost, bufRecv)) 103 { 104 ShowErrorMsg(); //显示错误信息 105 return ExitClient(CLIENT_API_ERROR); //退出 106 } 107 //显示服务器的应答 108 cout << bufRecv << endl; 109 110 //退出 111 return ExitClient(CLIENT_EXIT_OK); 112 } 113 114 115 /* 116 * 显示错误信息 117 */ 118 void ShowErrorMsg(void) 119 { 120 int nErrCode = WSAGetLastError();//获取错误代码 121 122 HLOCAL hlocal = NULL; 123 124 //获取错误的文本字符串 125 BOOL fOk = FormatMessage( 126 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 127 NULL, nErrCode, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 128 (PTSTR)&hlocal, 0, NULL); 129 130 //显示错误信息 131 if (hlocal != NULL) 132 { 133 MessageBox(NULL, (LPCWSTR)LocalLock(hlocal), (LPCWSTR)"CLIENT ERROR", MB_OK); 134 LocalFree(hlocal); 135 } 136 } 137 138 139 /* 140 * 初始化成员变量 141 */ 142 void InitMember(void) 143 { 144 //初始化读和写缓冲区 145 memset(bufRecv, 0, MAX_NUM_BUF); 146 memset(bufSend, 0, MAX_NUM_BUF); 147 //初始化 148 sHost = INVALID_SOCKET; 149 //没有连接状态 150 bConning = FALSE; 151 } 152 153 /* 154 * 退出 155 */ 156 int ExitClient(int nExit) 157 { 158 closesocket(sHost); //关闭套接字 159 WSACleanup(); //卸载Windows sockets DLL 清理内存 160 161 //显示退出信息 162 cout << "客户端正在退出..." << endl; 163 Sleep(20000); 164 return nExit; //退出 165 } 166 167 168 /* 169 * 读取一行数据 170 */ 171 BOOL RecvLine(SOCKET s, char* buf) 172 { 173 BOOL retVal = TRUE; //返回值 174 BOOL bLineEnd = FALSE; //行结束 175 int nReadLen = 0; //读入字节数 176 int nDataLen = 0; //数据长度 177 while (!bLineEnd && bConning) //与客户端连接 没有换行 178 { 179 nReadLen = recv(s, buf + nDataLen, 1, 0);//每次接收一个字节 180 //错误处理 181 if (SOCKET_ERROR == nReadLen) 182 { 183 retVal = FALSE; //读数据失败 184 break; //跳出循环 185 } 186 187 if (0 == nReadLen)//客户端关闭 188 { 189 retVal = FALSE; //读数据失败 190 break; //跳出循环 191 } 192 193 //读入数据 194 if ('\n' == *(buf + nDataLen)) //换行符 195 { 196 bLineEnd = TRUE; //接收数据结束 197 } 198 else { 199 nDataLen += nReadLen; //增加数据长度 200 } 201 } 202 203 return retVal; 204 }