socket多線程java
1. java socket客戶端還用多線程嗎
服務端要同時為很多客戶工作的話,簡單的設計就是使用多線程,每個線程為一個客戶工作。客戶端通常不需要特別多的線程,但是一般也需要一個工作線程負責和服務端的協議處理,一個界面的線程,否則如果網路阻塞,用戶的體驗會很不好(界面總是卡殼)。當然簡單學習的話,客戶端用單線程也是可以的。
例子代碼很多Java編程的書里都有,可以在網上搜索一下。推薦還是去下載一本Java網路編程的電子書吧,不然光看實例源代碼,一些基本概念和處理方法不太容易明白為什麼要這樣做的。
2. java socket多線程的問題可以多個線程使用同一個socket嗎
可以寫個demo試一下啊,應該是可以的,socket接收到的消息只能被其中一個線程接收。線程1 和2 接受到的肯定不是同一個消息。會有先後之分。看你怎麼控制。比如從接收的消息是ABCD,那麼這相當於一個資源。線程1和2在這里拿消息,拿到之後,socket裡面就少了,比如線程1拿到AB,線程2拿到CD
3. java一個Socket連接多線程是否能操作兩個讀取流
可以啊 ,不過需要新建兩個實現Runnable 借口的類,重寫run方法,一個實現讀取,另一個實現輸出的功能。再用兩條線程分別操作這兩個方法。
4. 用Java的socket編程實現c/s結構程序
今天太晚了,改天給你做一個,記得提醒我,這個如果只是要個簡單的,我半個小時就搞定了
給我個郵箱
現在給貼出我的代碼: 整個結構分兩個工程
1。服務端工程NioServer.java: 採用nio 方式的非同步socket通信,不僅可以實現你的伺服器還可以讓你多學習一下什麼是nio
2。客戶端工程UserClient.java: 採用Swing技術畫了一個簡單的UI界面,比較土,原因是我沒那麼多時間去設計界面,你需要的話可以自己去修改得漂亮點,相信不難
現在貼工程1:
package com.net;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NioServer {
public static final int SERVERPORT=5555;
public static final String USERNAME="wangrong";
public static final String PASSWORD="123456";
public static final String ISACK="ACK";
public static final String ISNAK="NAK!";
// Selector selector;//選擇器
// SelectionKey key;//key。 一個key代表一個Selector 在NIO通道上的注冊,類似主鍵;
// //取得這個Key後就可以對Selector在通道上進行操作
private ByteBuffer echoBuffer = ByteBuffer.allocate( 1024 );// 通道數據緩沖區
public NioServer(){
}
public static void main(String[] args) throws IOException {
NioServer ns=new NioServer();
ns.BuildNioServer();
}
public void BuildNioServer() throws IOException{
/////////////////////////////////////////////////////////
///////先對服務端的ServerSocket進行注冊,注冊到Selector ////
/////////////////////////////////////////////////////////
ServerSocketChannel ssc = ServerSocketChannel.open();//新建NIO通道
ssc.configureBlocking( false );//使通道為非阻塞
ServerSocket ss = ssc.socket();//創建基於NIO通道的socket連接
//新建socket通道的埠
ss.bind(new InetSocketAddress("127.0.0.1",SERVERPORT));
Selector selector=Selector.open();//獲取一個選擇器
//將NIO通道選綁定到擇器,當然綁定後分配的主鍵為skey
SelectionKey skey = ssc.register( selector, SelectionKey.OP_ACCEPT );
////////////////////////////////////////////////////////////////////
//// 接收客戶端的連接Socket,並將此Socket也接連注冊到Selector ////
///////////////////////////////////////////////////////////////////
while(true){
int num = selector.select();//獲取通道內是否有選擇器的關心事件
if(num<1){continue; }
Set selectedKeys = selector.selectedKeys();//獲取通道內關心事件的集合
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {//遍歷每個事件
try{
SelectionKey key = (SelectionKey)it.next();
//有一個新聯接接入事件,服務端事件
if ((key.readyOps() & SelectionKey.OP_ACCEPT)
== SelectionKey.OP_ACCEPT) {
// 接收這個新連接
ServerSocketChannel serverChanel = (ServerSocketChannel)key.channel();
//從serverSocketChannel中創建出與客戶端的連接socketChannel
SocketChannel sc = serverChanel.accept();
sc.configureBlocking( false );
// Add the new connection to the selector
// 把新連接注冊到選擇器
SelectionKey newKey = sc.register( selector,
SelectionKey.OP_READ );
it.remove();
System.out.println( "Got connection from "+sc );
}else
//讀客戶端數據的事件,此時有客戶端發數據過來,客戶端事件
if((key.readyOps() & SelectionKey.OP_READ)
== SelectionKey.OP_READ){
// 讀取數據
SocketChannel sc = (SocketChannel)key.channel();
int bytesEchoed = 0;
while((bytesEchoed = sc.read(echoBuffer))> 0){
System.out.println("bytesEchoed:"+bytesEchoed);
}
echoBuffer.flip();
System.out.println("limet:"+echoBuffer.limit());
byte [] content = new byte[echoBuffer.limit()];
echoBuffer.get(content);
String result=new String(content);
doPost(result,sc);
echoBuffer.clear();
it.remove();
}
}catch(Exception e){}
}
}
}
public void doPost(String str,SocketChannel sc){
boolean isok=false;
int index=str.indexOf('|');
if(index>0){
String name=str.substring(0,index);
String pswd=str.substring(index+1);
if(pswd==null){pswd="";}
if(name!=null){
if(name.equals(USERNAME)
&& pswd.equals(PASSWORD)
){
isok=true;
}else{
isok=false;
}
}else{
isok=false;
}
}else{
isok=false;
}
String result="";
if(isok){
result="ACK";
}else{
result="NAK!";
}
ByteBuffer bb = ByteBuffer.allocate( result.length() );
bb.put(result.getBytes());
bb.flip();
try {
sc.write(bb);
} catch (IOException e) {
e.printStackTrace();
}
bb.clear();
}
}
下面貼工程2
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class UserClient implements ActionListener{
JFrame jf;
JPanel jp;
JLabel label_name;
JLabel label_pswd;
JTextField userName;
JButton jb;
JPasswordField paswrd;
JLabel hintStr;
public UserClient (){
jf=new JFrame("XXX 登陸系統");
jp=new JPanel();
jf.setContentPane(jp);
jf.setPreferredSize(new Dimension(350,220));
jp.setPreferredSize(new Dimension(350,220));
jp.setBackground(Color.gray);
label_name=new JLabel();
label_name.setPreferredSize(new Dimension(150,30));
label_name.setText("請輸入帳戶(數字或英文):");
userName=new JTextField();
userName.setPreferredSize(new Dimension(150,30));
jp.add(label_name);
jp.add(userName);
label_pswd=new JLabel();
label_pswd.setPreferredSize(new Dimension(150,30));
label_pswd.setText("請輸入密碼:");
jp.add(label_pswd);
paswrd=new JPasswordField();
paswrd.setPreferredSize(new Dimension(150,30));
jp.add(paswrd);
jb=new JButton("OK");
jb.setPreferredSize(new Dimension(150,30));
jb.setText("確 定");
jb.addActionListener( this);
jp.add(jb);
hintStr=new JLabel();
hintStr.setPreferredSize(new Dimension(210,40));
hintStr.setText("");
hintStr.setForeground(Color.RED);
jp.add(hintStr);
jf.pack();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private String name;
private String pswd;
public void actionPerformed(ActionEvent e) {
name=userName.getText().trim();
pswd=new String(paswrd.getPassword());
if(pswd==null){
pswd="";
}else{
pswd=pswd.trim();
}
if(name!=null && name.length()>0){
hintStr.setText("正在驗證客戶端,請稍候...");
start();
}
}
OutputStream os;
Socket s;
InputStream is;
public void start(){
//建立聯網線程
new Thread(new Runnable(){
public void run() {
try {
s=new Socket("127.0.0.1",5555);
//寫
os=s.getOutputStream();
os.write(name.getBytes());
os.write('|');//用戶名與密碼用"|"分隔
os.write(pswd.getBytes());
os.flush();
//讀內容
Thread.sleep(1000);
is=s.getInputStream();
int len=is.available();
System.out.println("len:"+len);
byte[] bytes=new byte[len];
is.read(bytes);
String resut=new String(bytes);
System.out.println("resut:"+resut);
//TODO 這里通過返回結果處理
if(resut.equals("ACK")){
hintStr.setText("驗證成功,歡迎光臨!");
}else{
paswrd.setText(null);
hintStr.setText("用戶名或密碼錯誤,請重新輸入");
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
// try {
// os.close();
// is.close();
// s.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}).start();
}
public static void main(String[] args) {
new UserClient();
}
}
5. JAVA程序完成伺服器和客戶端的SOCKET通訊,要求伺服器使用多線程接收和處理多個客戶端訪問請求
1. 客戶端程序
import java.io.*;
import java.net.*;
public class TalkClient {
public static void main(String args[]) {
try{
Socket socket=new Socket("127.0.0.1",4700);
//向本機的4700埠發出客戶請求
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標准輸入設備構造BufferedReader對象
PrintWriter os=new PrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,並構造PrintWriter對象
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,並構造相應的BufferedReader對象
String readline;
readline=sin.readLine(); //從系統標准輸入讀入一字元串
while(!readline.equals("bye")){
//若從標准輸入讀入的字元串為 "bye"則停止循環
os.println(readline);
//將從系統標准輸入讀入的字元串輸出到Server
os.flush();
//刷新輸出流,使Server馬上收到該字元串
System.out.println("Client:"+readline);
//在系統標准輸出上列印讀入的字元串
System.out.println("Server:"+is.readLine());
//從Server讀入一字元串,並列印到標准輸出上
readline=sin.readLine(); //從系統標准輸入讀入一字元串
} //繼續循環
os.close(); //關閉Socket輸出流
is.close(); //關閉Socket輸入流
socket.close(); //關閉Socket
}catch(Exception e) {
System.out.println("Error"+e); //出錯,則列印出錯信息
}
}
}
2. 伺服器端程序
import java.io.*;
import java.net.*;
import java.applet.Applet;
public class TalkServer{
public static void main(String args[]) {
try{
ServerSocket server=null;
try{
server=new ServerSocket(4700);
//創建一個ServerSocket在埠4700監聽客戶請求
}catch(Exception e) {
System.out.println("can not listen to:"+e);
//出錯,列印出錯信息
}
Socket socket=null;
try{
socket=server.accept();
//使用accept()阻塞等待客戶請求,有客戶
//請求到來則產生一個Socket對象,並繼續執行
}catch(Exception e) {
System.out.println("Error."+e);
//出錯,列印出錯信息
}
String line;
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,並構造相應的BufferedReader對象
PrintWriter os=newPrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,並構造PrintWriter對象
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標准輸入設備構造BufferedReader對象
System.out.println("Client:"+is.readLine());
//在標准輸出上列印從客戶端讀入的字元串
line=sin.readLine();
//從標准輸入讀入一字元串
while(!line.equals("bye")){
//如果該字元串為 "bye",則停止循環
os.println(line);
//向客戶端輸出該字元串
os.flush();
//刷新輸出流,使Client馬上收到該字元串
System.out.println("Server:"+line);
//在系統標准輸出上列印讀入的字元串
System.out.println("Client:"+is.readLine());
//從Client讀入一字元串,並列印到標准輸出上
line=sin.readLine();
//從系統標准輸入讀入一字元串
} //繼續循環
os.close(); //關閉Socket輸出流
is.close(); //關閉Socket輸入流
socket.close(); //關閉Socket
server.close(); //關閉ServerSocket
}catch(Exception e){
System.out.println("Error:"+e);
//出錯,列印出錯信息
}
}}