📄 broardcast.cpp
字号:
// broardcast.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include <winsock.h>
#pragma comment(lib, "Ws2_32.lib")
#define PORT 8888
#define MAX_LENGTH 256
#define MY_SOCK WM_USER+0x100
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK Send(HWND, UINT, WPARAM, LPARAM);
//发送条处理函数
BOOL broadsend(TCHAR* buffer); //发送函数
BOOL broadinit(); //初始化
BOOL broadrecv(TCHAR* buffer); //接收函数
VOID broadclose(); //关闭套接字
BOOL broadselect(HWND hWnd, long lEvent);
TCHAR serveraddr[MAX_LENGTH]; //存放主机名
TCHAR FAR* lpServeraddr = serveraddr;
TCHAR ipaddr[MAX_LENGTH]; //存放主机ip地址信息
TCHAR FAR* lpIpaddr = ipaddr;
TCHAR recvBuffer[30][3*MAX_LENGTH];
TCHAR FAR* lpBuffer[30]; //消息缓冲队列
int rear = 0, front = 1;
SOCKET s = 0; //套接字
struct sockaddr_in broadsock;
struct hostent* hostaddr; //在得到本机ip时要用到
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_BROARDCAST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BROARDCAST);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_BROARDCAST);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_BROARDCAST;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
int textX = 0, textY = 0;
WSADATA wsaData;
switch (message)
{
case WM_CREATE:
if(WSAStartup(0x101, &wsaData))
{
MessageBox(hWnd, "初始化Ws2_32.lib失败", "ERROR!", MB_OK);
PostMessage(hWnd, WM_DESTROY, NULL, NULL);
}//初始化Winsock动态链接库
if(!broadinit())
{
MessageBox(hWnd, "初始化Winsock失败", "ERROR!", MB_OK);
PostMessage(hWnd, WM_DESTROY, NULL, NULL);
}//初始化套接字
if(!broadselect(hWnd, FD_READ))
{
MessageBox(hWnd, "异步选择失败", "ERROR!", MB_OK);
PostMessage(hWnd, WM_DESTROY, NULL, NULL);
}//参见原理部分的WSAAsyncSocket的用法
gethostname(lpServeraddr, MAX_LENGTH);
//得到主机名
hostaddr = gethostbyname(lpServeraddr);
//通过主机名得到ip等一系列信息
lpIpaddr=inet_ntoa (*(struct in_addr *)hostaddr->h_addr_list[0]);
//将四字节ip格式化为字符窜
int j;
for(j = 0; j<30; j++)
{
lpBuffer[j] = recvBuffer[j];
memset(lpBuffer[j], 0, 3*MAX_LENGTH);
}
//初始化消息缓冲区
//MessageBox(hWnd, lpIpaddr, "", 0);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_SEND:
DialogBox(hInst, (LPCTSTR)IDD_BROAD, hWnd, (DLGPROC)Send);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case MY_SOCK:
switch(lParam)
{
case FD_READ:
//得到数据到达的消息,便启动broadrecv接收
if(!broadrecv(lpBuffer[rear]))
MessageBox(hWnd, "接收失败!", "ERROR!", MB_OK);
else
{
if(front<29) front++;
else front=0;
memset(lpBuffer[front], 0, 3*MAX_LENGTH);
if(rear<29) rear++;
else rear=0;
//以上是对消息缓存队列的操作
//其原理是循环队列,超过30条记录就把第一条擦掉
}
InvalidateRect(hWnd, NULL, TRUE);
break;
default:
break;
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
//以下为将暂存消息队列中的字符窜输出到窗口中
int i;
for(i = 0; i<30; i++)
TextOut(hdc, 0, 20*i+20, lpBuffer[i], strlen(lpBuffer[i]));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
broadclose();
WSACleanup();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
LRESULT CALLBACK Send(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
//这个是发送内容对话框的处理程序
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == ID_CANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
if (LOWORD(wParam) == ID_SEND)
{
//如果点击了发送按钮,就把文本框中的内容加上ip和主机信息发送
TCHAR content[MAX_LENGTH];
GetDlgItemText(hDlg, IDC_CONTENT, content, MAX_LENGTH);
TCHAR sendBuffer[768] = {0};
//以下为格式化字符窜
wsprintf(sendBuffer, "主机:%s,IP%s,广播:%s", lpServeraddr, lpIpaddr, content);
if(!broadsend(sendBuffer))
MessageBox(hDlg, "发送失败!", "ERROR!", MB_OK);
EndDialog(hDlg, LOWORD(wParam));
}
break;
}
return FALSE;
}
BOOL broadsend(TCHAR* buffer)
{
struct sockaddr_in target;
target.sin_family = AF_INET;
target.sin_addr.S_un.S_addr = INADDR_BROADCAST;
target.sin_port = htons(PORT);
//以上是填充目标地址块
if((sendto(s, buffer, 3*MAX_LENGTH, 0, (struct sockaddr FAR*)&target,
sizeof(SOCKADDR))) == SOCKET_ERROR)
return FALSE;
//发送数据buffer
return TRUE;
}
BOOL broadinit()
{
BOOL optval = TRUE;
if((s = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
return FALSE;
//初始化套接字s,记住,只有SOCK_DGRAM(无连接方式)才支持广播
broadsock.sin_family = AF_INET;
broadsock.sin_addr.S_un.S_addr = 0;
broadsock.sin_port = htons(PORT);
//填充本机地址块,其中PORT为8888
if(bind(s, (LPSOCKADDR)&broadsock, sizeof(broadsock)))
return FALSE;
//绑定端口
if(setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char FAR*)&optval,
sizeof(optval)) == SOCKET_ERROR)
//记住,这一步将套接字设为可以广播的格式
return FALSE;
return TRUE;
}
BOOL broadrecv(TCHAR* buffer)
{
int errno, len;
int from_len = sizeof(SOCKADDR);
struct sockaddr_in from;
if((len = recvfrom(s, buffer, 3*MAX_LENGTH, 0, (struct sockaddr FAR*)&from,
(int FAR*)&from_len)) == SOCKET_ERROR)
{
errno = WSAGetLastError();
//上面这种方式是网络编程常用的方法
//针对错误码进行不同的处理,可以使程序更强壮
if(errno == WSAEWOULDBLOCK)
//套接字定为非阻塞,但接收操作将被阻塞
return TRUE;
else { //发生错误
broadclose();
return FALSE;
}
}
if(len == 0)
{
return FALSE; //接收错误
}
return TRUE;
}
VOID broadclose()
{
if(s){
closesocket(s);
//关闭套接字
s = 0;
}
}
BOOL broadselect(HWND hWnd, long lEvent)
{
if(WSAAsyncSelect(s, hWnd, MY_SOCK, lEvent) == SOCKET_ERROR) {
//WSAAsyncSelect的用处非常大,具体的说明详见实验原理部分
return FALSE;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -