【通信协议及编码】实验1:阻塞、非阻塞和异步模式套接字客户机与服务器程序


一、实验目的

  1. 掌握WinSock2 API编程框架;
  2. 掌握阻塞模式和非阻赛模式套接字的原理和编程方法;
  3. 掌握异步套接字的原理和编程方法;

二、实验环境

  1. 操作系统:WINDOWS 7及以上
  2. 开发工具:Microsoft VisualBasic6.0
  3. 实验设备:PC

三、实验内容

  1. 编程实现: 设计一个可完成阻塞模式套接字通信的客户机和服务器,并完成联机调试,能要求:收到客户机的连接请求后向客户机发送一条友好消息“服务器说:有朋自远方来,不亦乐乎”。
  2. 编程实现: 设计一个可完成非阻塞模式套接字通信的客户机和服务器,并实现联机调试。
  3. 编程实现: 设计一个可完成异步模式套接字通信的客户机和服务器,并实现联机调试。

1.阻塞模式套接字通信的客户机和服务器

1.代码:
服务器:

#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
int main() {
	WSADATA WsaDat;
	if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0) {
		std::cout << "WinSock服务初始化失败!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}
	SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (Socket == INVALID_SOCKET) {
		std::cout << "创建套接字失败!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}

	SOCKADDR_IN serverInf;
	serverInf.sin_family = AF_INET;
	serverInf.sin_addr.s_addr = INADDR_ANY;
	serverInf.sin_port = htons(8888);
	if (bind(Socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
	{
		std::cout << "不能绑定地址信息到套接字!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}
	listen(Socket, 1);
	SOCKET TempSock = SOCKET_ERROR;
	while (TempSock == SOCKET_ERROR) {
		std::cout << "服务器:正在等待来自客户机的连接!\r\n";
		TempSock = accept(Socket, NULL, NULL);
	}
	Socket = TempSock;
	std::cout << "服务器:有客户机连接到达!\r\n\r\n";
	char * szMessage = (char*) "服务器说:有朋自远方来,不亦乐乎\r\n";
	send(Socket, szMessage, strlen(szMessage), 0);
	shutdown(Socket, SD_SEND);

	closesocket(Socket);
	//关闭
	WSACleanup();
	system("pause");
	return 0;
}

客户机:

#include<iostream>
#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
	//初始化WinSock服务
	WSADATA WsaDat;
	if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0) {
		std::cout << "WinSock错误 - WinSock服务初始化失败!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}

	//创建套接字
	SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (Socket == INVALID_SOCKET) {
		std::cout << "套接字错误 - 创建套接字失败!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}

	//主机名解析
	struct  hostent*host;
	if ((host = gethostbyname("localhost")) == NULL)
	{
		std::cout << "主机名解析失败!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}

	//配置套接字要访问的服务器的地址结构信息
	SOCKADDR_IN SockAddr;
	SockAddr.sin_port = htons(8888);
	SockAddr.sin_family = AF_INET;
	SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

	//连接服务器
	if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
		std::cout << "服务器连接失败!\r\n";
		WSACleanup();
		system("pause");
		return 0;
	}

	//从服务器接收信息并显示
	char buffer[1024];
	memset(buffer, 0, 1023);
	int inDataLength = recv(Socket, buffer, 1024, 0);
	std::cout << buffer;

	//断开套接字连接
	shutdown(Socket, SD_SEND);
	//关闭套接字
	closesocket(Socket);
	WSACleanup();
	system("pause");
	return 0;
}

2.运行结果:
服务器:
在这里插入图片描述
客户机:
在这里插入图片描述
客户机服务器连接失败:
在这里插入图片描述

2.非阻塞模式套接字通信的客户机和服务器

1.代码:
服务器:

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
	WSADATA WsaDat;
	if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
	{
		std::cout << "Winsock服务初始化失败!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (Socket == INVALID_SOCKET)
	{
		std::cout << "创建套接字失败!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	SOCKADDR_IN serverInf;
	serverInf.sin_family = AF_INET;
	serverInf.sin_addr.s_addr = INADDR_ANY;
	serverInf.sin_port = htons(8888);

	if (bind(Socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
	{
		std::cout << "套接字绑定失败!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	listen(Socket, 1);

	SOCKET TempSock = SOCKET_ERROR;
	while (TempSock == SOCKET_ERROR)
	{
		std::cout << "服务器:正在等待客户机连接...\r\n";
		TempSock = accept(Socket, NULL, NULL);
	}

	//  iMode!=0表示阻塞模式
	u_long iMode = 1;
	ioctlsocket(Socket, FIONBIO, &iMode);

	Socket = TempSock;
	std::cout << "服务器说:有新客户机连接到达!\r\n\r\n";

	// 主循环
	for (;;)
	{
		char *szMessage = (char*)"非阻塞服务器说:有朋自远方来来,不亦乐乎\r\n";
		send(Socket, szMessage, strlen(szMessage), 0);

		int nError = WSAGetLastError();
		if (nError != WSAEWOULDBLOCK && nError != 0)
		{
			std::cout << "Winsock错误码为: " << nError << "\r\n";
			std::cout << "客户机断开连接!\r\n";

			// 断开套接字,不允许发送,可以接收
			shutdown(Socket, SD_SEND);

			// 关闭套接字
			closesocket(Socket);

			break;
		}

		Sleep(1000);
	}

	WSACleanup();
	system("PAUSE");
	return 0;
}

客户机:

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main(void)
{
	WSADATA WsaDat;
	if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
	{
		std::cout<<"Winsock错误 - Winsock初始化失败\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	// 创建套接字

	SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(Socket==INVALID_SOCKET)
	{
		std::cout<<"Winsock错误 - 创建套接字失败!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	// 解析主机名
	struct hostent *host;
	if((host=gethostbyname("localhost"))==NULL)
	{
		std::cout<<"解析主机名失败!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	// 配置套接字地址结构信息
	SOCKADDR_IN SockAddr;
	SockAddr.sin_port=htons(8888);
	SockAddr.sin_family=AF_INET;
	SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);

	// 连接服务器
	if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0)
	{
		std::cout<<"连接服务器失败!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}

	//  iMode!=0是阻塞模式
	u_long iMode=1;
	ioctlsocket(Socket,FIONBIO,&iMode);

	// 主循环
	for(;;)
	{
		// 接收服务器信息
		char buffer[1024];
		memset(buffer,0,1023);
		int inDataLength=recv(Socket,buffer,1024,0);
		std::cout<<buffer;

		int nError=WSAGetLastError();
		if(nError!=WSAEWOULDBLOCK&&nError!=0)
		{
			std::cout<<"Winsock错误码为: "<<nError<<"\r\n";
			std::cout<<"服务器断开连接!\r\n";
			// 断开套接字,只能接收不能发送
			shutdown(Socket,SD_SEND);

			// 关闭套接字
			closesocket(Socket);

			break;
		}
		Sleep(1000);
	}

	WSACleanup();
	system("PAUSE");
	return 0;
}

2.运行结果:
服务器:
在这里插入图片描述
客户机:
在这里插入图片描述
客户机服务器连接失败:
在这里插入图片描述
连接时客户机断开:
在这里插入图片描述

3.异步模式套接字通信的客户机和服务器

1.代码:
服务器:

#include <winsock2.h>
#include <windows.h>

#pragma comment(lib,"ws2_32.lib")

#define IDC_EDIT_IN		101
#define IDC_EDIT_OUT		102
#define IDC_MAIN_BUTTON		103
#define WM_SOCKET		104

int nPort = 5555;

HWND hEditIn = NULL;
HWND hEditOut = NULL;
SOCKET Socket = NULL;
char szHistory[10000];
sockaddr sockAddrClient;

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
	WNDCLASSEX wClass;
	ZeroMemory(&wClass, sizeof(WNDCLASSEX));
	wClass.cbClsExtra = NULL;
	wClass.cbSize = sizeof(WNDCLASSEX);
	wClass.cbWndExtra = NULL;
	wClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wClass.hIcon = NULL;
	wClass.hIconSm = NULL;
	wClass.hInstance = hInst;
	wClass.lpfnWndProc = (WNDPROC)WinProc;
	wClass.lpszClassName = "Window Class";
	wClass.lpszMenuName = NULL;
	wClass.style = CS_HREDRAW | CS_VREDRAW;

	if (!RegisterClassEx(&wClass))
	{
		int nResult = GetLastError();
		MessageBox(NULL,
			"窗体类注册失败!\r\n错误码:",
			"窗体类注册错误",
			MB_ICONERROR);
	}

	HWND hWnd = CreateWindowEx(NULL,
		"Window Class",
		"异步套接字服务器",
		WS_OVERLAPPEDWINDOW,
		200,
		200,
		500,
		400,
		NULL,
		NULL,
		hInst,
		NULL);

	if (!hWnd)
	{
		int nResult = GetLastError();

		MessageBox(NULL,
			"创建窗体失败\r\n错误码:",
			"窗体创建错误",
			MB_ICONERROR);
	}

	ShowWindow(hWnd, nShowCmd);

	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDC_MAIN_BUTTON:
			{
				char szBuffer[1024];
				ZeroMemory(szBuffer, sizeof(szBuffer));

				SendMessage(hEditOut,
					WM_GETTEXT,
					sizeof(szBuffer),
					reinterpret_cast<LPARAM>(szBuffer));

				send(Socket, szBuffer, strlen(szBuffer), 0);

				SendMessage(hEditOut, WM_SETTEXT, NULL, (LPARAM)"");
			}
			break;
		}
		break;
	case WM_CREATE:
		{
			ZeroMemory(szHistory, sizeof(szHistory));

			// 创建接收消息框
			hEditIn = CreateWindowEx(WS_EX_CLIENTEDGE,
				"EDIT",
				"",
				WS_CHILD | WS_VISIBLE | ES_MULTILINE |
				ES_AUTOVSCROLL | ES_AUTOHSCROLL,
				50,
				100,
				400,
				200,
				hWnd,
				(HMENU)IDC_EDIT_IN,
				GetModuleHandle(NULL),
				NULL);
			if (!hEditIn)
			{
				MessageBox(hWnd,
					"不能创建接收消息框",
					"错误",
					MB_OK | MB_ICONERROR);
			}
			HGDIOBJ hfDefault = GetStockObject(DEFAULT_GUI_FONT);
			SendMessage(hEditIn,
				WM_SETFONT,
				(WPARAM)hfDefault,
				MAKELPARAM(FALSE, 0));
			SendMessage(hEditIn,
				WM_SETTEXT,
				NULL,
				(LPARAM)"正在等待客户机连接...");

			// 创建发送消息框
			hEditOut = CreateWindowEx(WS_EX_CLIENTEDGE,
				"EDIT",
				"",
				WS_CHILD | WS_VISIBLE | ES_MULTILINE |
				ES_AUTOVSCROLL | ES_AUTOHSCROLL,
				50,
				30,
				400,
				60,
				hWnd,
				(HMENU)IDC_EDIT_IN,
				GetModuleHandle(NULL),
				NULL);
			if (!hEditOut)
			{
				MessageBox(hWnd,
					"不能创建发送消息框",
					"错误",
					MB_OK | MB_ICONERROR);
			}

			SendMessage(hEditOut,
				WM_SETFONT,
				(WPARAM)hfDefault,
				MAKELPARAM(FALSE, 0));
			SendMessage(hEditOut,
				WM_SETTEXT,
				NULL,
				(LPARAM)"在此处输入要发送的消息...");

			// 创建发送按钮
			HWND hWndButton = CreateWindow(
				"BUTTON",
				"发送",
				WS_TABSTOP | WS_VISIBLE |
				WS_CHILD | BS_DEFPUSHBUTTON,
				50,
				310,
				75,
				23,
				hWnd,
				(HMENU)IDC_MAIN_BUTTON,
				GetModuleHandle(NULL),
				NULL);

			SendMessage(hWndButton,
				WM_SETFONT,
				(WPARAM)hfDefault,
				MAKELPARAM(FALSE, 0));

			WSADATA WsaDat;
			int nResult = WSAStartup(MAKEWORD(2, 2), &WsaDat);
			if (nResult != 0)
			{
				MessageBox(hWnd,
					"Winsock服务初始化失败",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
			if (Socket == INVALID_SOCKET)
			{
				MessageBox(hWnd,
					"创建套接字失败",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			SOCKADDR_IN SockAddr;
			SockAddr.sin_port = htons(nPort);
			SockAddr.sin_family = AF_INET;
			SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);

			if (bind(Socket, (LPSOCKADDR)&SockAddr, sizeof(SockAddr)) == SOCKET_ERROR)
			{
				MessageBox(hWnd, "套接字绑定失败", "错误", MB_OK);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			nResult = WSAAsyncSelect(Socket,
				hWnd,
				WM_SOCKET,
				(FD_CLOSE | FD_ACCEPT | FD_READ));
			if (nResult)
			{
				MessageBox(hWnd,
					"WSAAsyncSelect 套接字异步事件初始化失败",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			if (listen(Socket, (1)) == SOCKET_ERROR)
			{
				MessageBox(hWnd,
					"服务器套接字侦听失败!",
					"错误",
					MB_OK);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}
		}
		break;

	case WM_DESTROY:
		{
			PostQuitMessage(0);
			shutdown(Socket, SD_BOTH);
			closesocket(Socket);
			WSACleanup();
			return 0;
		}
		break;

	case WM_SOCKET:
		{
			switch (WSAGETSELECTEVENT(lParam))
			{
			case FD_READ:
				{
					char szIncoming[1024];
					ZeroMemory(szIncoming, sizeof(szIncoming));

					int inDataLength = recv(Socket,
						(char*)szIncoming,
						sizeof(szIncoming) / sizeof(szIncoming[0]),
						0);

					strncat(szHistory, szIncoming, inDataLength);
					strcat(szHistory, "\r\n");

					SendMessage(hEditIn,
						WM_SETTEXT,
						sizeof(szIncoming) - 1,
						reinterpret_cast<LPARAM>(&szHistory));
				}
				break;

			case FD_CLOSE:
				{
					MessageBox(hWnd,
						"客户机关闭了到服务器的连接",
						"连接关闭",
						MB_ICONINFORMATION | MB_OK);
					closesocket(Socket);
					SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				}
				break;

			case FD_ACCEPT:
				{
					int size = sizeof(sockaddr);
					Socket = accept(wParam, &sockAddrClient, &size);
					if (Socket == INVALID_SOCKET)
					{
						int nret = WSAGetLastError();
						WSACleanup();
					}
					SendMessage(hEditIn,
						WM_SETTEXT,
						NULL,
						(LPARAM)"客户机已经成功连接到服务器");
				}
				break;
			}
		}
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}

客户机:

#include <winsock2.h>
#include <windows.h>

#pragma comment(lib,"ws2_32.lib")

#define IDC_EDIT_IN		101
#define IDC_EDIT_OUT		102
#define IDC_MAIN_BUTTON		103
#define WM_SOCKET		104

char *szServer = (char*)"localhost";
int nPort = 5555;

HWND hEditIn = NULL;
HWND hEditOut = NULL;
SOCKET Socket = NULL;
char szHistory[10000];

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
	WNDCLASSEX wClass;
	ZeroMemory(&wClass, sizeof(WNDCLASSEX));
	wClass.cbClsExtra = NULL;
	wClass.cbSize = sizeof(WNDCLASSEX);
	wClass.cbWndExtra = NULL;
	wClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wClass.hIcon = NULL;
	wClass.hIconSm = NULL;
	wClass.hInstance = hInst;
	wClass.lpfnWndProc = (WNDPROC)WinProc;
	wClass.lpszClassName = "Window Class";
	wClass.lpszMenuName = NULL;
	wClass.style = CS_HREDRAW | CS_VREDRAW;

	if (!RegisterClassEx(&wClass))
	{
		int nResult = GetLastError();
		MessageBox(NULL,
			"窗体类注册失败!\r\n错误码:" + nResult,
			"窗体类错误",
			MB_ICONERROR);
	}

	HWND hWnd = CreateWindowEx(NULL,
		"Window Class",
		"异步套接字客户机",
		WS_OVERLAPPEDWINDOW,
		200,
		200,
		500,
		400,
		NULL,
		NULL,
		hInst,
		NULL);

	if (!hWnd)
	{
		int nResult = GetLastError();
		MessageBox(NULL,
			"创建窗体失败\r\n错误码:",
			"创建窗体失败",
			MB_ICONERROR);
	}

	ShowWindow(hWnd, nShowCmd);

	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CREATE:
		{
			ZeroMemory(szHistory, sizeof(szHistory));

			// 创建接收消息框
			hEditIn = CreateWindowEx(WS_EX_CLIENTEDGE,
				"EDIT",
				"",
				WS_CHILD | WS_VISIBLE | ES_MULTILINE |
				ES_AUTOVSCROLL | ES_AUTOHSCROLL,
				50,
				100,
				400,
				200,
				hWnd,
				(HMENU)IDC_EDIT_IN,
				GetModuleHandle(NULL),
				NULL);
			if (!hEditIn)
			{
				MessageBox(hWnd,
					"不能创建接收消息框",
					"错误",
					MB_OK | MB_ICONERROR);
			}
			HGDIOBJ hfDefault = GetStockObject(DEFAULT_GUI_FONT);
			SendMessage(hEditIn,
				WM_SETFONT,
				(WPARAM)hfDefault,
				MAKELPARAM(FALSE, 0));
			SendMessage(hEditIn,
				WM_SETTEXT,
				NULL,
				(LPARAM)"正在连接服务器...");

			//创建发送消息框
			hEditOut = CreateWindowEx(WS_EX_CLIENTEDGE,
				"EDIT",
				"",
				WS_CHILD | WS_VISIBLE | ES_MULTILINE |
				ES_AUTOVSCROLL | ES_AUTOHSCROLL,
				50,
				30,
				400,
				60,
				hWnd,
				(HMENU)IDC_EDIT_IN,
				GetModuleHandle(NULL),
				NULL);
			if (!hEditOut)
			{
				MessageBox(hWnd,
					"不能创建发送消息框",
					"错误",
					MB_OK | MB_ICONERROR);
			}

			SendMessage(hEditOut,
				WM_SETFONT, (WPARAM)hfDefault,
				MAKELPARAM(FALSE, 0));
			SendMessage(hEditOut,
				WM_SETTEXT,
				NULL,
				(LPARAM)"在这里输入要发送的消息...");

			// Create a push button
			HWND hWndButton = CreateWindow(
				"BUTTON",
				"发送",
				WS_TABSTOP | WS_VISIBLE |
				WS_CHILD | BS_DEFPUSHBUTTON,
				50,
				310,
				75,
				23,
				hWnd,
				(HMENU)IDC_MAIN_BUTTON,
				GetModuleHandle(NULL),
				NULL);

			SendMessage(hWndButton,
				WM_SETFONT,
				(WPARAM)hfDefault,
				MAKELPARAM(FALSE, 0));

			// 配置Winsock套接字
			WSADATA WsaDat;
			int nResult = WSAStartup(MAKEWORD(2, 2), &WsaDat);
			if (nResult != 0)
			{
				MessageBox(hWnd,
					"Winsock初始化失败",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
			if (Socket == INVALID_SOCKET)
			{
				MessageBox(hWnd,
					"创建套接字失败",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			nResult = WSAAsyncSelect(Socket, hWnd, WM_SOCKET, (FD_CLOSE | FD_READ));
			if (nResult)
			{
				MessageBox(hWnd,
					"WSAAsyncSelect异步套接字失败",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			// 主机名称解析
			struct hostent *host;
			if ((host = gethostbyname(szServer)) == NULL)
			{
				MessageBox(hWnd,
					"不能解析主机名",
					"严重错误",
					MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}

			// 配置套接字地址信息
			SOCKADDR_IN SockAddr;
			SockAddr.sin_port = htons(nPort);
			SockAddr.sin_family = AF_INET;
			SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

			connect(Socket, (LPSOCKADDR)(&SockAddr), sizeof(SockAddr));
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDC_MAIN_BUTTON:
			{
				char szBuffer[1024];

				int test = sizeof(szBuffer);
				ZeroMemory(szBuffer, sizeof(szBuffer));

				SendMessage(hEditOut,
					WM_GETTEXT,
					sizeof(szBuffer),
					reinterpret_cast<LPARAM>(szBuffer));
				send(Socket, szBuffer, strlen(szBuffer), 0);
				SendMessage(hEditOut, WM_SETTEXT, NULL, (LPARAM)"");
			}
			break;
		}
		break;

	case WM_DESTROY:
		{
			PostQuitMessage(0);
			shutdown(Socket, SD_BOTH);
			closesocket(Socket);
			WSACleanup();
			return 0;
		}
		break;

	case WM_SOCKET:
		{
			if (WSAGETSELECTERROR(lParam))
			{
				MessageBox(hWnd,
					"连接服务器失败",
					"错误",
					MB_OK | MB_ICONERROR);
				SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				break;
			}
			switch (WSAGETSELECTEVENT(lParam))
			{
			case FD_READ:
				{
					char szIncoming[1024];
					ZeroMemory(szIncoming, sizeof(szIncoming));

					int inDataLength = recv(Socket,
						(char*)szIncoming,
						sizeof(szIncoming) / sizeof(szIncoming[0]),
						0);

					strncat(szHistory, szIncoming, inDataLength);
					strcat(szHistory, "\r\n");

					SendMessage(hEditIn,
						WM_SETTEXT,
						sizeof(szIncoming) - 1,
						reinterpret_cast<LPARAM>(&szHistory));
				}
				break;

			case FD_CLOSE:
				{
					MessageBox(hWnd,
						"服务器关闭了连接",
						"连接关闭",
						MB_ICONINFORMATION | MB_OK);
					closesocket(Socket);
					SendMessage(hWnd, WM_DESTROY, NULL, NULL);
				}
				break;
			}
		}
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}

2.运行结果截图:
服务器:
在这里插入图片描述
客户机:
在这里插入图片描述
发送消息:
在这里插入图片描述
在这里插入图片描述
连接关闭:
在这里插入图片描述
在这里插入图片描述


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值