基于对话框的套接字编程
实验目的
- 理解Win32窗口应用程序的窗口机制、消息机制等工作原理。
- 掌握Win32窗口应用程序的程序框架和实现步骤。
- 掌握基于对话框的套接字编程方法和步骤。
二、实验内容
在VC++编程环境下,实现一个基于对话框的流式套接字C/S模式应用程序。要求建立Socket连接后,客户端可向服务器端发送信息并显示信息内容,服务器端可接收信息并显示信息的内容。
程序运行界面如下图所示:
提示:服务器端对话框主要控件设置可参考下表,客户端可对照设置。
要求:本实验需要提供服务端程序和客户端程序源代码压缩包。
三、实验原理
Windows 程序设计是一种事件驱动方式的程序设计模式,主要是基于消息的。一个完整的Win32窗体程序的实现步骤大概可以分为6步:
1.设计窗口类(使用WNDCLASS类)
2.注册窗口(RegisterClass()函数)
3.创建窗口(CreateWindow()函数)
4.显示及更新窗口(ShowWindow()、updateWindow())
5.通过循环取消息(GetMessage())
6.实现窗口过程(WinProc函数)
对话框本质上也是一个窗体,其工作机制与窗体的工作机制相同。不过,在VS2012编程环境中设计对话框,可以充分利用图形化界面工具,在设计和实现上更为简单。一般简单的界面应用程序推荐使用对话框来实现。
四、实验步骤
1.编写程序,运行服务器端跟客户端
2.服务器端,创建IP及端口,客户端连接次服务器地址,成功连接
3.客户端发送数据,服务器点击接收数据
五、实验小结
通过实验,理解Win32窗口应用程序的窗口机制、消息机制等工作原理,掌握Win32窗口应用程序的程序框架和实现步骤,掌握基于对话框的套接字编程方法和步骤。
六、源码
服务器
#include "stdafx.h"
#include "TE03_Win32TcpServ.h"
//编程添加
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
//编程添加
SOCKET sockServer,sockConnect;
SOCKADDR_IN addrServer,addrClient;
char ip[16],port[5];
char sendBuf[256],recvBuf[256];
char clientBuf[999]="客户端: >",serverBuf[999]="服务器: >";
int addrLen=sizeof(SOCKADDR);
// 此代码模块中包含的函数的前向声明:
BOOL InitInstance(HINSTANCE, int);
INT_PTR CALLBACK TcpSrvProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TE03_WIN32TCPSERV));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd =CreateDialog(hInstance, MAKEINTRESOURCE(IDD_TCPSRV), GetDesktopWindow(), TcpSrvProc);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// “TCP服务器端”框的消息处理程序。
INT_PTR CALLBACK TcpSrvProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
SetDlgItemText(hDlg,IDC_SrvIP_IPC,"127.0.0.1"); //设置ip文本框的内容
SetDlgItemText(hDlg,IDC_PORT_EDIT,"5566"); //设置端口文本框的内容
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2), &wsaData))
{
MessageBox(hDlg,"Winsock加载失败","警告",0);
WSACleanup();
}
return (INT_PTR)TRUE;
case WM_COMMAND:
switch(LOWORD(wParam) )
{
case IDC_QUIT_BUTTON: //单击了退出按钮
EndDialog(hDlg, LOWORD(wParam));
closesocket(sockServer); //关闭套接字
WSACleanup(); //卸载WinSock协议栈
return TRUE;
case IDC_CREATE_BUTTON: //单击了创建服务器按钮
GetDlgItemText(hDlg,IDC_SrvIP_IPC,ip,16); //获取编辑框中的IP值
GetDlgItemText(hDlg,IDC_PORT_EDIT,port,5);
EnableWindow(GetDlgItem(hDlg,IDC_CREATE_BUTTON),FALSE); //禁用按钮
sockServer=socket(AF_INET,SOCK_STREAM,0);
addrServer.sin_family=AF_INET;
addrServer.sin_addr.S_un.S_addr=inet_addr(ip);
addrServer.sin_port=htons(atoi(port));
bind(sockServer,(SOCKADDR*) &addrServer,addrLen); //绑定套接字
listen(sockServer,5); //监听
sockConnect=accept(sockServer,(SOCKADDR*) &addrClient,&addrLen);//接受连接
if(sockConnect!=INVALID_SOCKET)
SendDlgItemMessage(hDlg,IDC_RECVBUF_LISTBOX,LB_ADDSTRING,0,(LPARAM)"客户端已经连接上");
break;
case IDC_RECV_BUTTON: //单击了接收按钮
recv(sockConnect,recvBuf,256,0);
strcat(clientBuf,recvBuf);
//将接收到的消息添加到列表框中
SendDlgItemMessage(hDlg,IDC_RECVBUF_LISTBOX,LB_ADDSTRING,0,(LPARAM)clientBuf);
strcpy(clientBuf, "客户端: >");
break;
}//switch(LOWORD(wParam) )
}//switch (message)
return (INT_PTR)FALSE;
}
客户端
#include "stdafx.h"
#include "L09_TcpClient.h"
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
SOCKET sockClient; //声明客户端套接字
SOCKADDR_IN addrServer;
// 此代码模块中包含的函数的前向声明:
BOOL InitInstance(HINSTANCE, int);
INT_PTR CALLBACK TcpClientProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_L09_TCPCLIENT, szWindowClass, MAX_LOADSTRING);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_L09_TCPCLIENT));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_TCPCLIENT), GetDesktopWindow(), TcpClientProc);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// “TCP客户端”框的消息处理程序。
INT_PTR CALLBACK TcpClientProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
char ip[16], port[5];
char sendbuf[256],recvbuf[256];
char serbuf[256]="服务器: >", clibuf[256]="客户端: >";
int len =sizeof(SOCKADDR);
switch (message)
{
case WM_INITDIALOG:
SetDlgItemText(hDlg,IDC_IP_IPC,"127.0.0.1");
SetDlgItemText(hDlg,IDC_PORT_EDIT,"5566");
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData); //加载协议栈
sockClient=socket(AF_INET,SOCK_STREAM,0); //创建套接字
return (INT_PTR)TRUE;
case WM_COMMAND:
{
switch(LOWORD(wParam)) {
case IDC_QUIT_BUTTON: //单击了退出按钮
EndDialog(hDlg, LOWORD(wParam));
closesocket(sockClient);
WSACleanup();
break;
case IDC_CONN_BUTTON: //单击了“连接服务器”按钮
GetDlgItemText(hDlg,IDC_IP_IPC,ip,16); //获取ip
GetDlgItemText(hDlg,IDC_PORT_EDIT,port,5);
EnableWindow(GetDlgItem(hDlg,IDC_CONN_BUTTON),FALSE); //禁用连接按钮
addrServer.sin_family=AF_INET;
addrServer.sin_addr.S_un.S_addr=inet_addr(ip);
addrServer.sin_port=htons(atoi(port));
if(connect(sockClient,(SOCKADDR*)&addrServer,sizeof(SOCKADDR)))
MessageBox(NULL,"客户端连接服务器失败","警告",0);
else
MessageBox(NULL,"客户端连接服务器成功","通知",0);
break;
case IDC_SEND_BUTTON: //单击了“发送”按钮
GetDlgItemText(hDlg,IDC_SEND_EDIT,sendbuf,256); //获得发送框的内容
send(sockClient,sendbuf,strlen(sendbuf)+1,0); //发送消息
SetDlgItemText(hDlg,IDC_SEND_EDIT,""); //清空发送框
strcat(clibuf,sendbuf);
SendDlgItemMessage(hDlg,IDC_RECV_LISTBOX,LB_ADDSTRING,0,(LPARAM)clibuf);
strcpy(clibuf, "客户端: >"); //重新给字符串赋值
break;
}
}//case WM_COMMAND:
}
return (INT_PTR)FALSE;
}