孙鑫:第十五讲 多线程聊天室程序创建

孙鑫15课:多线程与聊天室程序的创建

程序,进程(32位进程,分配2的32次方,4GB,2GB内核分区,2GB用户分区。),线程

进程是线程容器。真正完成代码执行的是线程。主线程:main(),winmain()

下面创建一个多线程的程序:(WIN32控制台程序 )

#include <windows.h>//访问windows API函数

#include <iostream.h>//C++标准输入输出流头文件

 

int index=0;

int tickets=100;

HANDLE hmutex;

DWORD WINAPI ThreadProc1(LPVOID lpParameter)

{

       while(true)

       {

WaitForSingleObject(hmutex,INFINITE);

              if (tickets>0)

              {

                     cout<<"thread1 is selling ticket:"<<tickets--<<endl;

              }

              else

                     break;

ReleaseMutex(hmutex);

             

       }

       return 0;

 

}

 

DWORD WINAPI ThreadProc2(LPVOID lpParameter)

{

       while(true)

       {

WaitForSingleObject(hmutex,INFINITE);

              if (tickets>0)

              {

                     cout<<"thread2 is selling ticket:"<<tickets--<<endl;

              }

              else

                     break;

ReleaseMutex(hmutex);

       }

              return 0;

      

}

void main()

{

       HANDLE thread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);

       CloseHandle(thread1);

       HANDLE thread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);

       CloseHandle(thread2);

//关闭线程1句柄,刚创建就关闭,关闭句柄,并没有终止线程1,只是表示在主线程中,只是对线程1的引用不感兴趣,所以关闭。

//让线程1的内核使用对象计数器减1。当线程1执行完后,线程1使用计数器清空,系统会释放线程1内核对象。

       //如果在主线程中没有关闭线程1句柄,则在线程1使用完后,也不会将线程使用计数器-1,则程序执行完后,

       //也不会释放线程1内核对象,只有等到进程终止的时候,才会清空。

       //所以应该在不使用线程句柄的时候将其关闭,让线程内核引用计数-1。

       //while(index++<1000)

       //cout<<"main is running"<<endl;

hmutex=CreateMutex(NULL,false,NULL);//main 函数不拥有对互CHI对象的拥有权

       Sleep(1000);

 

}//主线程退出,进程退出。则在此进程中包含的线程全部退出。

互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。

互斥对象包含一个使用数量,一个线程ID和一个计数器。

ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。

 

判断先前是否有一个应用实例在运行的代码:(要//创建一个命名的互斥对象)

hMutex=CreateMutex(NULL,TRUE,"tickets");

if(hMutex)

{

        if(ERROR_ALREADY_EXISTS==GetLastError())

        {

               cout<<"only instance can run!"<<endl;

               return;

        }

}

 

下面编写一个网络聊天室程序:

创建一个基于对话框的程序。

在BOOL CChatApp::InitInstance()中加上下面代码:

if (AfxSocketInit(  )==0)//AfxSocketInit(  )加载套接字版本1.1.//

        //This function also ensures that ::WSACleanup is called for you before the application terminates.

 

{

        AfxMessageBox("加载套接字版本失败!");

        return FALSE;

}

在StdAfx.h中加上#include <Afxsock.h>。

给CChatDlg加上

private:

socket m_socket;

并在CChatDlg的构造函数中将m_socket=0

和一个成员函数:BOOL CChatDlg::InitSock()

BOOL CChatDlg::InitSock()

{

    m_socket=socket(AF_INET,SOCK_DGRAM,0);

if (INVALID_SOCKET==m_socket)

{

        MessageBox("套接字创建失败!");

        return FALSE;

}

 

SOCKADDR_IN addrsk;

addrsk.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

addrsk.sin_family=AF_INET;

addrsk.sin_port=htons(6000);

 

if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&addrsk,sizeof(SOCKADDR_IN)))

{

        MessageBox("绑定失败!");

        closesocket(m_socket);

        return FALSE;

}

return TRUE;

}

在BOOL CChatDlg::OnInitDialog()中加下面代码:

if(FALSE==InitSock())

{

        MessageBox("初始化套接字失败!");

        return FALSE;

}

recvfrom如果没有数据过来,它会阻塞进程执行。因此把接收数据操作放到一个单独的线程中完成。

给ChatDlg.h 增加一个成员结构体的变量:

struct RECVPARAM

{

        SOCKET sock;

        HWND   hwnd;

};

在BOOL CChatDlg::OnInitDialog()中增加下面代码:

RECVPARAM *recvparam=new RECVPARAM;

recvparam->sock=m_socket;

recvparam->hwnd=m_hWnd;

HANDLE handle=CreateThread(NULL,0,RecvProc,(LPVOID)recvparam,0,NULL);

CloseHandle(handle);

在这本例中把接收函数写成是CChatDlg的成员函数

在class CChatDlg : public CDialog中加

static  DWORD WINAPI RecvProc(LPVOID lpParameter);//static的话,这个函数不属于哪个成员变量,它只属于这个类本身。所以在其它函数中可以直接调用这个函数。

DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)

{

HWND hnd=((RECVPARAM*)lpParameter)->hwnd;

SOCKET sk=((RECVPARAM*)lpParameter)->sock;

delete lpParameter; 

SOCKADDR_IN skaddr;

int len=sizeof(SOCKADDR);

char recvBuf[100];

char tempBuf[200];

while(1)

{

        if(SOCKET_ERROR==recvfrom(sk,recvBuf,100,0,(SOCKADDR*)&skaddr,&len))

               break;//终止循环

        else

        {

            sprintf(tempBuf,"%s say:%s",inet_ntoa(skaddr.sin_addr),recvBuf);

               ::PostMessage(hnd,WM_RECVDATA,0,(LPARAM )tempBuf);

        }

}

 

   return 0;

}

在ChatDlg.H中

#define  WM_RECVDATA WM_USER+1

在class CChatDlg : public CDialog中加入:

afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);

在BEGIN_MESSAGE_MAP(CChatDlg, CDialog)

//{{AFX_MSG_MAP(CChatDlg)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_BN_CLICKED(IDC_BTN_SEND, OnBtnSend)

ON_MESSAGE(WM_RECVDATA,OnRecvData)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

END_MESSAGE_MAP()中加入上面红色的一句

void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lParam)
{
 CString str=(char*)lParam;
 CString strTemp;
 GetDlgItemText(IDC_EDIT_RECV,strTemp);
 str+="\r\n";
 str+=strTemp;
 SetDlgItemText(IDC_EDIT_RECV,str);
}

发送按钮的代码如下:

//记得让接收文本框的属性加一 个多行

void CChatDlg::OnBtnSend()

{

// TODO: Add your control notification handler code here

DWORD dwIP;

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

 

SOCKADDR_IN addrTo;

addrTo.sin_family=AF_INET;

addrTo.sin_port=htons(6000);

addrTo.sin_addr.S_un.S_addr=htonl(dwIP);

 

CString strSend;

GetDlgItemText(IDC_EDIT_SEND,strSend);

sendto(m_socket,strSend,strSend.GetLength()+1,0,

        (SOCKADDR*)&addrTo,sizeof(SOCKADDR));

SetDlgItemText(IDC_EDIT_SEND,"");

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
孙鑫.java web开发详解: xml xslt servlet jsp深入剖析与实例应用》是一本介绍Java Web开发技术的书籍。本书以XML、XSLT、Servlet和JSP为核心内容,旨在帮助读者全面了解并深入理解这些技术的应用和原理。 首先,书中详细介绍了XML(可扩展标记语言)的基本语法和应用场景。XML是一种用于存储和传输数据的标记语言,具有结构清晰、易于扩展和可读性好的特点。本书通过实例演示了XML的使用方法,包括如何创建、解析和操作XML文档。同时,还介绍了XML的相关技术和工具,如DTD(文档类型定义)、Schema(模式)、XPath(路径语言)和XSLT(可扩展样式表语言转换)。 接着,书中系统地介绍了Servlet和JSP的应用和原理。Servlet是Java编写的服务器端程序,用于响应客户端的请求并生成动态内容。JSP(Java Server Pages)是一种将Java代码嵌入到HTML中的技术,用于生成动态网页。本书通过实例展示了如何使用Servlet和JSP开发Web应用,包括处理请求和响应、会话管理、数据库访问等方面的内容。 最后,本书还深入剖析了XML、XSLT、Servlet和JSP的底层原理,包括HTTP协议、请求和响应的处理流程、Web容器的工作原理等。通过深入理解这些原理,读者能够更好地进行Web应用的开发和调优。 总之,《孙鑫.java web开发详解: xml xslt servlet jsp深入剖析与实例应用》是一本全面介绍Java Web开发技术的书籍,通过详细的实例和剖析,帮助读者掌握XML、XSLT、Servlet和JSP的应用和原理,提升Web开发的技能和水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值