給你一個我寫的示例,用的是基於TCP的Socket技術,你鍛煉一下,改一改,不會改再找我!
客戶端:
import java.net.Socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class TcpClient {
public static void main(String[] args) throws Exception
{
//創建客戶端Socket服務,並且制定主機和ank
Socket s = new Socket("192.168.1.104",10002);//連接固定的主機和埠
//為了發送數據,獲取Socket中的輸入輸出流
OutputStream out = s.getOutputStream();
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String line = null;
//讀取伺服器發過來的數據
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
while((line = br.readLine())!=null)
{
out.write(line.getBytes());
if("886".equals(line))
break;
int len = in.read(buf);
String content = new String(buf,0,len);
System.out.println("Server:"+content);
}
s.close();
}
}
伺服器:
/*
* 需求分析:
* 使用TCP協議,寫伺服器端。做到伺服器能收到客戶端的信息,也能向客戶端發送信息
* */
package JavaNetProgramming;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class TcpServer {
public static void main(String[] args) throws Exception
{
//建立伺服器的Socket服務,並且監聽一個埠
ServerSocket ss = new ServerSocket(10002);
Socket s = ss.accept();
InputStream is = s.getInputStream();
//從伺服器端向客戶端發送數據
OutputStream out = s.getOutputStream();
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String line = null;
while(true)
{
//通過accept()方法獲得客戶端傳過來的Socket對象
// System.out.println("getByNanme():"+s.getInetAddress());
System.out.print("getHostAddress():"+s.getInetAddress().getHostAddress());
//獲取客戶端發過來的數據,就要使用客戶端對象的讀取流來讀取數據
byte[] buf = new byte[1024];
int len = is.read(buf);//把流中數據讀到位元組數組中
String content = new String(buf,0,len);
System.out.println(" "+content);
if("886".equals(content))
break;
while((line = br.readLine())!=null)
{
out.write(line.getBytes());
break;
}
}
s.close(); //循環內有判斷語句,這句話才不出錯
ss.close();
}
}
㈡ 求教編程做出一個兩人多人之間簡單的聊天程序
製作人: CK.y ,匯成建築企業管理Q:610089144
僅供參考,大家要學會自己製作,很有成就感的啊!! 用 Java 作後台,開發一個 C / S 架構的多人聊天程序。首先,設計用戶界面。
一、界面設計
界面的元件全部使用 Flash CS3 自帶的組件:
首先,放入 TextInput 組件(實例名 input_txt),作為用戶輸入;
再放入 Button 組件(實例名 submit_btn),用於提交輸入的信息;
最後放入 TextArea 組件(實例名 output_txt),顯示聊天信息。
二、組件參數初始化
由於客戶端代碼不是很多,我們這次就寫在動作幀上:
// ************ 組件參數初始化 ************
submit_btn.label = "發送消息";
output_txt.editable = false;
// 設置各組件中字體的大小
input_txt.setStyle("textFormat", new TextFormat(null, 15));
output_txt.setStyle("textFormat", new TextFormat(null, 15));
submit_btn.setStyle("textFormat", new TextFormat(null, 15, null, true));
// 當按下回車或點擊 submit_btn 按鈕後調用事件處理函數
submit_btn.addEventListener(MouseEvent.CLICK, sendMessage);
addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
// 事件處理函數
function onKeyDown(evt:KeyboardEvent):void {
if (evt.keyCode == Keyboard.ENTER) {
sendMessage(null);
}
}
function sendMessage(evt:Event):void {
// 測試:將 input_txt 的內容輸出到 output_txt 中
output_txt.appendText(input_txt.text + "\n");
// 清空 input_txt,並設置焦點到 input_txt
input_txt.text = "";
stage.focus = input_txt;
}
三、編寫客戶端 Socket
1. 首先,Socket 連接非常簡單:
var socket:Socket = new Socket();
socket.connect("127.0.0.1", 8888);
其中 connect() 方法中的兩個參數分別為是主機名和埠號(埠號盡量用 1024 以上)。好了,這樣就連接上了。接下來是讀寫的問題。
2. 向伺服器端寫入字元串:我們在 sendMessage() 方法中進行寫入操作,注意寫出的字串必需以回車(\n)結束:
function sendMessage(evt:Event):void {
var bytes:ByteArray = new ByteArray();
bytes.writeUTFBytes(input_txt.text + "\n");
socket.writeBytes(bytes);
socket.flush();
// 清空 input_txt,並設置焦點到 input_txt
input_txt.text = "";
stage.focus = input_txt;
}
3. 讀取伺服器端寫回的字元串:最後將伺服器發回的字元串輸出到 output_txt 文本域中:
// 當客戶端 socket 收到數據後會調用 readMessage() 函數
socket.addEventListener(ProgressEvent.SOCKET_DATA, readMessage);
function readMessage(evt:ProgressEvent):void {
output_txt.appendText(socket.readUTF() + "\n");
}
四、Flash 客戶端全部腳本
// ************ 組件參數初始化 ************
submit_btn.label = "發送消息";
output_txt.editable = false;
input_txt.setStyle("textFormat", new TextFormat(null, 15));
output_txt.setStyle("textFormat", new TextFormat(null, 15));
submit_btn.setStyle("textFormat", new TextFormat(null, 15, null, true));
submit_btn.addEventListener(MouseEvent.CLICK, sendMessage);
addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
function onKeyDown(evt:KeyboardEvent):void {
if (evt.keyCode == Keyboard.ENTER) {
sendMessage(null);
}
}
function sendMessage(evt:Event):void {
var bytes:ByteArray = new ByteArray();
bytes.writeUTFBytes(input_txt.text + "\n");
socket.writeBytes(bytes);
socket.flush();
input_txt.text = "";
stage.focus = input_txt;
}
// ************ 客戶端 Socket ************
var socket:Socket = new Socket();
socket.connect("127.0.0.1", 8888);
socket.addEventListener(ProgressEvent.SOCKET_DATA, readMessage);
function readMessage(evt:ProgressEvent):void {
output_txt.appendText(socket.readUTF() + "\n");
}
五、編寫 Java 伺服器端 Socket
最後,我們需要編寫 Java 後台伺服器端的代碼。
首先,創建一個 ServerSocket 作為Socket 伺服器。當有客戶端連接後通過 accept() 方法即可得到客戶端的 Socket:
ServerSocket socketServer = new ServerSocket(8888);
System.out.println("伺服器已啟動,等待客戶端連接");
// accept() 方法是阻塞式的,當有客戶端連接成功後才繼續執行
Socket socket = socketServer.accept();
System.out.println("客戶端連接成功");
然後得到與客戶端的輸入流和輸出流(輸入流是客戶端連接到伺服器的管道,輸出流則是伺服器到客戶端的管道):
// 獲得輸入流和輸出流,輸入流為 BufferedReader 類型,輸出流為 DataOutputStream 類型
BufferedReader reader =
new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
DataOutputStream writer = new DataOutputStream(socket.getOutputStream());
拿到輸入輸出流以後,就可以通過輸入流(InputStream)讀取 Flash 客戶端發來的字元串,通過輸出流(OutputStream)向 Flash 客戶端寫字元串:
while (true) {
// readLine() 方法也是阻塞式的,當客戶端有消息發來就讀取,否則就一直等待
String msg = reader.readLine();
// 當客戶端發送的字元串為 null 時,說明客戶端已經關閉,此時退出循環
if (msg == null) {
System.out.println("客戶端已離開");
break;
}
// 將讀入的信息加工後再寫回客戶端
writer.writeUTF("寫回客戶端的" + msg);
}
以上是ServerSocket 與 AS 3 Socket 通信的基本原理。在實際應用中,會有多個客戶端連接這個ServerSocket,因此要創建一個多線程的 Socket 伺服器。
下面簡述一下多線程 Socket 伺服器原理:當socketServer.accept() 之後就需要實例化一個線程對象,在該對象中持有socketServer.accept() 返回的 Socket 對象,然後讓線程跑起來執行讀寫操作。如果再來一個客戶端就再跑一個線程,同樣執行讀寫操作。同時,用一個 List 容器來管理這些對象。
最終伺服器端的代碼如下:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class FlashScoket {
private List<Client> clientList = new ArrayList<Client>();
public static void main(String[] args) {
new FlashScoket().runSocket();
}
private void runSocket() {
try {
ServerSocket socketServer = new ServerSocket(8888);
System.out.println("伺服器已啟動,等待客戶端連接");
while (true) {
// accept() 方法是阻塞式的,當有客戶端連接成功後才繼續執行
Socket socket = socketServer.accept();
System.out.println("客戶端連接成功");
// 實例化一個 Client 對象,並啟動該線程
Client client = new Client(socket);
clientList.add(client);
client.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class Client extends Thread {
private Socket socket;
private BufferedReader reader;
private DataOutputStream writer;
private Client(Socket socket) {
this.socket = socket;
try {
// 獲得輸入流和輸出流,輸入流為 BufferedReader 類型,輸出流為 DataOutputStream 類型
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
writer = new DataOutputStream(socket.getOutputStream());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (true) {
// readLine() 方法也是阻塞式的,當客戶端有消息發來就讀取,否則就一直等待
String msg = reader.readLine();
// 當客戶端發送的字元串為 null 時,說明客戶端已經關閉,此時退出循環
if (msg == null) {
clientList.remove(this);
System.out.println("客戶端已離開");
break;
}
// 將讀入的內容寫給每個客戶端
for (Iterator<Client> it = clientList.iterator(); it.hasNext();) {
Client client = it.next();
client.getWriter().writeUTF(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 關閉 socket 及相關資源
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public DataOutputStream getWriter() {
return writer;
}
}
}
六、補充技術
1. 如何測試?
* 首先要編譯FlashScoket —— javac FlashScoket
* 然後啟動FlashScoket —— java FlashScoket
* 最後將 Flash 發布為 exe 文件格式,同時開啟多個即可。
2. 自動跟蹤到最後一行:當收到新的消息時自動滾動到最後一行,在 readMessage() 方法中加入:
output_txt.verticalScrollBar.scrollPosition = output_txt.verticalScrollBar.maxScrollPosition;
3. 當出現輸入/輸出錯誤並導致發送或載入操作失敗時提示用戶,加入對IO_ERROR 的偵聽:
socket.addEventListener(IOErrorEvent.IO_ERROR, socketIOError);
function socketIOError(evt:IOErrorEvent):void {
output_txt.appendText("伺服器端尚未開啟,請稍後再試\n");
}
4. 在sendMessage() 中加入對空字元串的驗證,如果為空則 return:
if (input_txt.text == "") {
return;
}
5. 在消息前面顯示用戶名:大家可以製作一個登錄頁面,輸入用戶名,假設已將輸入的用戶名存放在 userName 變數中,在寫入時加進去:
var userName:String = "FL 車在臣";
在 sendMessage() 中相應改為:
bytes.writeUTFBytes(userName + " : " + input_txt.text + "\n");
6. 使用output_txt .htmlText 輸出文字,那麼相應的寫入格式可以調整為:
bytes.writeUTFBytes("<font color='#0000FF'>" + userName + " : </font>" + input_txt.text + "\n");
㈢ mfc socket 編程的流程是怎麼樣的
初始化socket
首先需要調用AfxSocketInit()函數來初始化我們的socket環境。
為了初始化sockets,我們需要調用AfxSocketInit()函數。它通常是在MFC中的InitInstance()函數中被調用的。如果我們用程序向導來創建socket程序的話,查看「use Windows Sockets」這個選項,然後選中它。它將會自動的為我們創建這個步驟了。(如果我們沒有選中這個選項的話,我們也可以手動添加這些代碼的。)這個函數的返回值顯示這個函數的調用成功或失敗。
BOOL CServerApp::InitInstance()
{....
if( AfxSocketInit() == FALSE)
{
AfxMessageBox("Sockets Could Not Be Initialized");
return FALSE;
}
...
}
創建Server Sockets
為了創建一個Server Socket,我們需要聲明一個CAyncSocket的變數或者我們自己定製的一個從AyncSocket或是Cscket繼承來的類的類型的變數。然後調用Create()函數,同時指定監聽的埠。這個函數的返回值顯示這個函數的調用成功或失敗。
UpdateData(TRUE);
m_sListener.Create(m_port);
if(m_sListener.Listen()==FALSE)
{
AfxMessageBox("Unable to Listen on that port,please try another port");
m_sListener.Close();
return;
}
創建Client Sockets
為了創建Client socket類,我們需要聲明一個CAyncSocket的變數或者我們自己定製的一個從AyncSocket或是Cscket繼承來的類的類型的變數。然後調用Create()函數,同時指定監聽的埠。這個函數的返回值顯示這個函數的調用成功或失敗。
m_sConnected.Create();
m_sConnected.Connect("server ip",port);
監聽客戶端的連接
創建了server socket以後,我們要進行監聽。調用Listen()函數。這個函數的返回值顯示這個函數的調用成功或失敗。
if( m_sListener.Listen()== FALSE)
{
AfxMessageBox("Unable to Listen on that port,please try another port");
m_sListener.Close();
return;
}
接受連接
連接請求要被接受accept,是用另外的socket,不是正在監聽的socket。請參看代碼。
void CXXXDlg::OnAccept()
{
CString strIP;
UINT port;
if(m_sListener.Accept(m_sConnected))
{
m_sConnected.GetSockName(strIP,port); //應該是GetPeerName,獲取對方的IP和port
m_status="Client Connected,IP :"+ strIP;
m_sConnected.Send("Connected To Server",strlen("Connected To Server"));
UpdateData(FALSE);
}
else
{
AfxMessageBox("Cannoot Accept Connection");
}
}
發送數據
數據放在一個buffer中或是結構體中,調用send()函數發送。
m_sConnected.Send(pBuf,iLen);
接受數據
調用receive()接受數據。
void CXXXrDlg::OnReceive()
{
char *pBuf =new char [1025];
CString strData;
int iLen;
iLen=m_sConnected.Receive(pBuf,1024);
if(iLen == SOCKET_ERROR)
{
AfxMessageBox("Could not Recieve");
}
else
{
pBuf[iLen]=NULL;
strData=pBuf;
m_recieveddata.Insert(m_recieveddata.GetLength(),strData);
//display in server
UpdateData(FALSE);
m_sConnected.Send(pBuf,iLen); //send the data back to the Client
delete pBuf;
}
}
關閉連接
m_sConnected.ShutDown(0); 停止發送數據
m_sConnected.ShutDown(1); 停止接受數據
m_sConnected.ShutDown(2); 停止發送接受數據
m_sConnected.Close();
編寫自己的socket類
在class view中選擇添加一個新類,設置它的基類為CAsyncSocket,在類向導的幫助下添加如下的一些函數。
class MySocket : public CAsyncSocket
{ // Attributes
public:
// Operations
public:
MySocket();
virtual ~MySocket();
// Overrides
public:
void SetParentDlg(CDialog *pDlg);// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(MySocket)
public:
virtual void OnAccept(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnOutOfBandData(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual void OnSend(int nErrorCode);
//}}AFX_VIRTUAL // Generated message map functions
//{{AFX_MSG(MySocket)
// NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG
protected:
private:
CDialog * m_pDlg;
};
設置「Parent Dialog」
調用這個socket類的SetParentDlg函數,保證當socket事件發生的時候這個窗體能接收到。
m_sListener.SetParentDlg(this);
m_sConnected.SetParentDlg(this);
建立Socket 事件和窗體成員函數之間的聯系
在這個窗體類中添加一些函數,比如void OnReceive(); void OnClose(); void OnAccept(); void OnConnect()等,它們會在我們編寫的的socket類中調用到。
void MySocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
if(nErrorCode==0)
{
((CServerDlg*)m_pDlg)->OnAccept();
}
CAsyncSocket::OnAccept(nErrorCode);
}