基于Socket和多线程的聊天程序实现

Java最后一道作业题竟然是写个多线程聊天工具。以前在一次实训中做过linux版的。当时就有人说Java版的实现比较简单,如今看来确实有理。尤其是在做UI上,不用像gtk那么麻烦。先将我搜到的资源与大家共享(亲测可用):

该网络聊天程序大致分为三个主要部分:客户端、服务器端和用户图形界面。各个部分的初步设计思想、流程及存储结构如下:

1.    程序整体框架:主程序监听一端口,等待客户接入;同时构造一个线程类,准备接管会话。当一个Socket会话产生后,将这个会话交给线程处理,然后主程序继续监听。

 

打开Socket

 

命 名

 

监听端口

 

建立连接

 

收发消息

 

关闭连接

 

打开Socket

 

 

连接服务器

 

收发消息

 

关闭连接

 

服务器端程序

 

客户端程序

 

2.    客户端(Client)

客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个端口。

3.    服务器端(Server)

服务器端,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。

4.    用户图形界面

用户图形界面方便程序与用户的交互,多个用户参加,完成会话功能,具体的设计要方便用户的使用,直观清晰,简洁明了,友好美观。

5.    存储结构

下面列出主要存储结构或变量:

存储结构、变量、对象

类型

说明

post

InetAddress

标识IP地址

Port

int

标识端口

Server [ ]

ServerThread

服务器端连接数

Client [ ]

Socket

客户端连接数

Client(String ip,int p,Face chat)

public

Client类成员函数

Public void run()

Void

Client、Server类成员函数

Server(int port,Face chat)

public

Server类成员函数

Face()

Public

Face类成员函数

1.服务器端

服务器端主要是使用ServerSocket类,相当于服务器Socket,用来监听试图进入的连接,当新的连接建立后,该类为他们实例化一个Socket对象,同时得到输入输出流,调用相应方法完成会话。

具体代码如下:

  1. package nupt.java.socket;  
  2. import java.awt.*;  
  3. import java.net.*;  
  4. import java.io.*;  
  5. public class Server extends Thread {  
  6. ServerSocket skt;   // ServerSocket类监听进入的连接,为每个新的连接产生一个Socket对象         
  7.     Socket Client[ ]=new Socket[10];  
  8.     Socket Client1=null;  
  9.     int i = 0;  
  10.     TextArea in;  
  11.     int port,k=0,l=0;  
  12.     PrintStream theOutputStream;  
  13.     Face chat;  
  14.     public Server(int port, Face chat) {  
  15.         try {  
  16.             this.port = port;  
  17.             skt = new ServerSocket(port);  
  18.             this.chat = chat;  
  19.         } catch (IOException e) {  
  20.             chat.ta.append(e.toString());  
  21.         }  
  22.     }  
  23.     public void run() {  
  24.         chat.ta.append("等待连线......");  
  25.         wh
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MFC(Microsoft Foundation Class)是微软公司提供的面向对象的 C++ 库,用于 Windows 程序的开发。基于 MFC 的多线程聊天程序可以使用 socket 技术实现。 以下是实现步骤: 1. 创建一个 MFC 应用程序,选择“多文档视图”类型。 2. 在应用程序类中添加两个变量:`CAsyncSocket m_server;` 和 `CPtrList m_socketList;`。`m_server` 用于监听客户端连接,`m_socketList` 用于存储连接的客户端 socket。 3. 在应用程序类的 InitInstance 函数中创建 socket: ``` if(!m_server.Create(8888)){ AfxMessageBox(_T("Failed to create server socket")); return FALSE; } if(!m_server.Listen()){ AfxMessageBox(_T("Failed to listen on server socket")); return FALSE; } ``` 4. 在应用程序类中添加一个成员函数 `OnAccept`,当有客户端连接时,该函数将被调用。在该函数中创建客户端 socket,并将其加入到 `m_socketList` 中。 ``` void CMyChatApp::OnAccept(){ CMySocket* pSocket = new CMySocket(); if(m_server.Accept(*pSocket)){ m_socketList.AddTail(pSocket); pSocket->AsyncSelect(FD_CLOSE | FD_READ); }else{ delete pSocket; } } ``` 5. 创建一个自定义 socket 类 `CMySocket`,继承自 `CAsyncSocket`。在该类中添加一个成员函数 `OnClose`,当客户端断开连接时,该函数将被调用。在该函数中将客户端 socket 从 `m_socketList` 中删除。 ``` void CMySocket::OnClose(int nErrorCode){ POSITION pos = theApp.m_socketList.Find(this); if(pos){ theApp.m_socketList.RemoveAt(pos); } delete this; } ``` 6. 在 `CMySocket` 类中添加一个成员函数 `OnReceive`,当有数据传入时,该函数将被调用。在该函数中读取数据并将其广播给所有连接的客户端。 ``` void CMySocket::OnReceive(int nErrorCode){ char buf[1024]; int len = Receive(buf, sizeof(buf)); if(len > 0){ buf[len] = '\0'; POSITION pos = theApp.m_socketList.GetHeadPosition(); while(pos){ CMySocket* pSocket = (CMySocket*)theApp.m_socketList.GetNext(pos); if(pSocket != this){ pSocket->Send(buf, len); } } } } ``` 7. 在主窗口中添加一个编辑框和一个按钮。在按钮的 Click 事件中创建一个客户端 socket,并连接到服务器。 ``` void CMyChatView::OnButtonConnect(){ CMySocket* pSocket = new CMySocket(); if(pSocket->Create()){ if(pSocket->Connect(_T("127.0.0.1"), 8888)){ pSocket->AsyncSelect(FD_CLOSE | FD_READ); theApp.m_socketList.AddTail(pSocket); }else{ delete pSocket; } }else{ delete pSocket; } } ``` 8. 在主窗口的 `OnDraw` 函数中添加一个定时器,每隔一段时间检查是否有新的客户端连接。在该函数中添加以下代码: ``` if(m_timer == 0){ m_timer = SetTimer(1, 1000, NULL); } ``` 9. 在主窗口类中添加一个成员变量 `UINT_PTR m_timer;`。 10. 实现定时器事件 `OnTimer`,在该事件中调用应用程序类的 `OnAccept` 函数检查是否有新的客户端连接。 ``` void CMyChatView::OnTimer(UINT_PTR nIDEvent){ if(nIDEvent == 1){ theApp.OnAccept(); } } ``` 11. 在主窗口中添加一个成员函数 `OnSocketNotify`,当有数据传入时,该函数将被调用。在该函数中读取数据并显示在编辑框中。 ``` void CMyChatView::OnSocketNotify(WPARAM wParam, LPARAM lParam){ CMySocket* pSocket = (CMySocket*)wParam; char buf[1024]; int len = pSocket->Receive(buf, sizeof(buf)); if(len > 0){ buf[len] = '\0'; CString strText; m_edit.GetWindowText(strText); strText += buf; m_edit.SetWindowText(strText); m_edit.LineScroll(m_edit.GetLineCount() - 1); } } ``` 12. 在主窗口类中添加一个成员变量 `HWND m_hWndServer;`。 13. 在主窗口的 Create 函数中创建一个隐藏的窗口,并将其消息处理函数设置为 `OnSocketNotify`。在该函数中添加以下代码: ``` m_hWndServer = CreateWindowEx(0, AfxRegisterWndClass(0), _T(""), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, AfxGetInstanceHandle(), NULL); ::SetWindowLong(m_hWndServer, GWL_USERDATA, (LONG)this); ``` 14. 在主窗口的 `OnClose` 函数中删除隐藏窗口。 ``` void CMyChatView::OnClose(){ ::DestroyWindow(m_hWndServer); CFormView::OnClose(); } ``` 15. 在主窗口的 `OnSize` 函数中调整编辑框的大小。 ``` void CMyChatView::OnSize(UINT nType, int cx, int cy){ CFormView::OnSize(nType, cx, cy); m_edit.MoveWindow(0, 0, cx, cy - 50); m_button.MoveWindow(cx - 100, cy - 50, 100, 50); } ``` 16. 在主窗口类中添加一个成员函数 `PostSocketNotify`,用于向隐藏窗口发送消息。在该函数中添加以下代码: ``` ::PostMessage(m_hWndServer, WM_SOCKET_NOTIFY, (WPARAM)pSocket, 0); ``` 17. 在主窗口类中添加一个宏定义 `WM_SOCKET_NOTIFY`。 ``` #define WM_SOCKET_NOTIFY (WM_USER + 1) ``` 18. 在隐藏窗口的消息处理函数 `OnSocketNotify` 中调用主窗口的 `OnSocketNotify` 函数。 ``` LRESULT CALLBACK CMyChatView::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch(message){ case WM_SOCKET_NOTIFY: { CMyChatView* pView = (CMyChatView*)::GetWindowLong(hWnd, GWL_USERDATA); pView->OnSocketNotify(wParam, lParam); break; } } return CFormView::WndProc(hWnd, message, wParam, lParam); } ``` 至此,基于 MFC 和 socket多线程聊天程序就完成了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值