📄 sdkserver.cpp
字号:
// SDKServer.cpp : Defines the entry point for the application.
//
//以下是一些头文件
#include "stdafx.h"
#include "winsock2.h"
#include "stdio.h"
#include "ctype.h"
#include "memory.h"
#include "string.h"
#include "winecho.h"
#define TRUE 1
#define FALSE 0
//一些变量
HANDLE hInst;
char buffer[2];
char *lpBuffer=&buffer[0];
int length=0;
SOCKET s,oldsocket;
int col=0,row=0;
//struct sockaddr_in dest_addr;
unsigned short port=5050;
//函数的声明
BOOL InitWindows(HANDLE); //[1],实现见[1]
long FAR PASCAL ServerProcedure(HWND,unsigned int,UINT,LONG); //[2],实现见[2]
VOID MessageToUser(HWND,LPSTR); //[3],实现见[3]
BOOL server(HWND); //[4],实现见[4]
BOOL set_socket(HWND,long); //[5],实现见[5]
BOOL make_socket(HWND); //[6],实现见[6]
BOOL accept_socket(HWND); //[7],实现见[7]
BOOL send_socket(HWND,int); //[8],实现见[8]
BOOL receive_socket(HWND,int *); //[9],实现见[9]
void close_socket(SOCKET); //[10],实现见[10]
void DisplayData(HWND hWnd,int len); //[11],实现见[11]
//Winmain函数
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
MSG msg;
//进行初始化应用程序实例和窗口类
if (!hPrevInstance)
{
if (! InitWindows(hInstance))
return (FALSE);
}
//在这里,只允许有一个服务器在工作
else
return(FALSE);
hInst=hInstance;
//创建窗口并且显示它
hWnd=CreateWindow("ServerClass",
"回音程序的服务器",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if (! hWnd)
return (FALSE);
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
EnableMenuItem(GetMenu(hWnd),IDM_EXIT,MF_DISABLED|MF_GRAYED);
//发送WM_USER消息,以便建立Socket
PostMessage(hWnd,WM_USER,(WPARAM)0,(LPARAM)0);
//进入消息循环
while(GetMessage(&msg,NULL,NULL,NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}
//实现[1] 初始化和注册窗口类
BOOL InitWindows(HANDLE hInstance)
{
WNDCLASS WndClass;
WndClass.style=CS_HREDRAW|CS_VREDRAW;
WndClass.lpfnWndProc=ServerProcedure;
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hInstance=(HINSTANCE)hInstance;
WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName=(LPSTR)"EchoMenu";
WndClass.lpszClassName=(LPSTR)"ServerClass";
//注册窗口类
return ( RegisterClass((PWNDCLASS)&WndClass) );
}
//实现[2]是回调函数,见最后一个实现
//实现[3]:给用户输出信息
void MessageToUser(HWND hWnd,LPSTR lpszWarning)
{
int flag=MessageBox(hWnd,lpszWarning,"Windows Server",
MB_OK|MB_ICONINFORMATION);
if(flag==0)
MessageBox(hWnd,"fail in messagebox","@@",MB_OK);
}
//实现[4]:服务器创建Socket,同时设置它所关心的事件
BOOL server(HWND hWnd)
{
//设置菜单项的有效和无效
EnableMenuItem(GetMenu(hWnd),IDM_START,MF_DISABLED|MF_GRAYED);
EnableMenuItem(GetMenu(hWnd),IDM_EXIT,MF_ENABLED);
//创建服务器Socket,见实现[6]
if (! make_socket(hWnd))
return (FALSE);
//设置服务器Socket所关心的事件:客户的请求连接到达,见实现[5]
if (! set_socket(hWnd,FD_ACCEPT|FD_CLOSE))
return (FALSE);
return (TRUE);
}
//实现[5]:设置网络事件函数
BOOL set_socket(HWND hWnd,long lEvent)
{
//设置网络事件,当事件发生时,将发送UM_SOCK的消息给hWnd窗口
if(WSAAsyncSelect(s,hWnd,UM_SOCK,lEvent)==SOCKET_ERROR)
{
MessageToUser(hWnd,"函数WSAAsyncSelect()出错");
return(FALSE);
}
return(TRUE);
}
//实现[6]:创建Socket、并且进行地址绑定
BOOL make_socket(HWND hWnd)
{
sockaddr_in sin;
// unsigned long on=1;
//建立流式Socket
s=socket(AF_INET,SOCK_STREAM,0);
if(s==INVALID_SOCKET)
{
MessageToUser(hWnd,"生成Socket出错");
return(FALSE);
}
//以下设置半相关,端口号为5050,IP地址为“202.115.111.222”
sin.sin_family=AF_INET;
sin.sin_addr.S_un.S_un_b.s_b1=202;
sin.sin_addr.S_un.S_un_b.s_b2=115;
sin.sin_addr.S_un.S_un_b.s_b3=111;
sin.sin_addr.S_un.S_un_b.s_b4=222;
sin.sin_port=htons(5050);
//Bind地址和端口号,成功时,返回的是0
if( int i=bind(s,(LPSOCKADDR)&sin,sizeof(sin)) )
{
i=WSAGetLastError();
close_socket(s);
return(FALSE);
}
//让服务器的Socket进行监听,成功的设置成监听状态时,返回的是0
if(listen(s,5))
return(FALSE);
return(TRUE);
}
//实现[7]:接收客户的请求,同时建立一个新的Socket进行请求处理
//而原Socket仍处于监听状态
BOOL accept_socket(HWND)
{
SOCKET newsocket;
struct sockaddr tcpaddr;
int len;
//建立新的Socket
len=sizeof(struct sockaddr);
newsocket=accept(s,(struct sockaddr FAR *)&tcpaddr,(int FAR *)&len);
if(newsocket==INVALID_SOCKET)
return(FALSE);
else
{
//保留监听Socket
//同时为处理新的请求Socket而让s代表新的Socket
oldsocket=s;
s=newsocket;
}
return(TRUE);
}
//实现[8]:发送数据的处理函数
//关于send函数的参数的含义可以参见1.2.3节
BOOL send_socket(HWND hWnd,int len)
{
if (send(s,lpBuffer,len,0)==SOCKET_ERROR)
return (FALSE);
return(TRUE);
}
//实现[9]:接收数据的处理函数
BOOL receive_socket(HWND hWnd,int *len)
{
int wantlength,err,reallength;
wantlength=*len;
//wantlength为打算接收的字节的个数
//reallength为实际接收的字节的个数
//关于recv函数的参数的含义可以参见1.2.3节
if( (reallength=recv(s,lpBuffer,wantlength,0)) == SOCKET_ERROR )
{
err=WSAGetLastError();
//当产生了非WSAEWOULDBLOCK的错误时,则认为接收数据没有成功。
//而产生了WSAEWOULDBLOCK的错误时,由于此程序中recv()被设置成非了阻塞模式,
//所以对它的调用将立即返回,同时产生了从错误信息,
//表示不出现阻塞而立即返回,这时程序可以继续向下运行。
if( err != WSAEWOULDBLOCK)
return(FALSE);
}
//返回实际接收的字节数
length=reallength;
return(TRUE);
}
//实现[10]:关闭Socket函数
void close_socket(SOCKET socket)
{
(void)closesocket(socket);
}
//实现[11]:显示客户发来的数据
void DisplayData(HWND hWnd,int len)
{
HDC dc;
int l;
char line[16];
buffer[len]=0;
if( dc=GetDC(hWnd) )
{
l=wsprintf((LPSTR)line,"%s",lpBuffer);
TextOut(dc,10*col,16*row,(LPSTR)line,l);
ReleaseDC(hWnd,dc);
}
col+=len;
if(col>40)
{
col=0;
row++;
}
}
//回调函数
long FAR PASCAL ServerProcedure(HWND hWnd,
unsigned message,
UINT wParam,
LONG lParam)
{
WSADATA wsaData;
int Status;
switch(message)
{
//分支1:建立和初始化Socket
case WM_USER:
//进行版本号的协商
Status=WSAStartup(0x101,&wsaData);
if(Status!=0)
{
MessageToUser(hWnd,"WSAStartup()函数失败");
PostQuitMessage(0);
}
//确认使用的版本号是1.1
if( LOBYTE(wsaData.wVersion)!=1 || HIBYTE(wsaData.wVersion)!=1)
{
MessageToUser(hWnd,"版本号协商没有成功");
WSACleanup();
PostQuitMessage(0);
}
/*
//建立和绑定服务器Socket
if(! server(hWnd))
{
MessageToUser(hWnd,"建立和绑定服务器Socket出错");
//使菜单有效和无效
EnableMenuItem(GetMenu(hWnd),IDM_START,MF_ENABLED);
EnableMenuItem(GetMenu(hWnd),IDM_EXIT,MF_DISABLED|MF_GRAYED);
}
*/
break;
//分支2:执行菜单命令
case WM_COMMAND:
//考虑不同的菜单命令
switch(wParam)
{
case IDM_START:
//建立和绑定服务器Socket
if(!server(hWnd))
{
MessageToUser(hWnd,"建立和绑定服务器Socket出错");
//使菜单有效和无效
EnableMenuItem(GetMenu(hWnd),IDM_START,MF_ENABLED);
EnableMenuItem(GetMenu(hWnd),IDM_EXIT,MF_DISABLED|MF_GRAYED);
}
break;
case IDM_EXIT:
//退出应用程序
WSACleanup();
PostQuitMessage(0);
break;
}
break;
//分支3:进行异步事件处理
case UM_SOCK:
//考虑不同的异步事件
switch(lParam)
{
//处理连接操作
case FD_ACCEPT:
if(! accept_socket(hWnd))
{
MessageToUser(hWnd,"接收Socket出错");
break;
}
set_socket(hWnd,FD_READ|FD_CLOSE);
break;
//处理读操作
case FD_READ:
length=2;
if(! receive_socket(hWnd,&length) )
{
MessageToUser(hWnd,"接收数据出错");
break;
}
//在服务器端显示客户传来的数据,调用了DisplayData()函数
DisplayData(hWnd,length);
//设置下面关心的是写事件的发生
set_socket(hWnd,FD_WRITE|FD_CLOSE);
break;
//处理写操作
case FD_WRITE:
if(! send_socket(hWnd,length))
{
MessageToUser(hWnd,"发送数据出错");
break;
}
//设置下面关心的是读事件的发生
set_socket(hWnd,FD_READ|FD_CLOSE);
break;
/*
//关闭连接
case FD_CLOSE:
if(WSAAsyncSelect(s,hWnd,0,0)==SOCKET_ERROR)
MessageToUser(hWnd,"事件设置错误");
MessageToUser(hWnd,"Socket被关闭了");
EnableMenuItem(GetMenu(hWnd),IDM_START,MF_ENABLED);
break;
*/
//默认处理
default:
if(WSAGETSELECTERROR(lParam)!=0)
{
MessageToUser(hWnd,"客户端的应用程序关闭了");
//恢复s成监听Socket
close_socket(s);
s=oldsocket;
//使菜单有效
EnableMenuItem(GetMenu(hWnd),IDM_START,MF_ENABLED);
}
break;
}
break;
//分支4:退出应用程序
case WM_DESTROY:
WSACleanup();
PostQuitMessage(0);
break;
//分支5:默认消息处理
default:
return(DefWindowProc(hWnd,message,wParam,lParam));
}
return(NULL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -