通過多執行緒實現非阻塞TCP通訊
阿新 • • 發佈:2019-02-17
在tcp通訊中,一般都是阻塞的,如果要實現非阻塞,我們可以使用多執行緒也可以使用nio中相關的類。這裡我使用的是多執行緒的方式實現非阻塞。
伺服器端:
1.建立ServerSocket物件,繫結監聽埠;
2.呼叫accept()方法對客戶端進行監聽;
3.使用多執行緒對使用者進行讀操作,並反饋;
客戶端:
1.建立Socket物件,通過IP和埠號和伺服器進行連線;
2.分別使用多執行緒對伺服器端進行讀寫操作;
程式碼如下:
伺服器端:
package sency.one;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private ServerSocket ss;
private int port = 8000;
public Server() throws IOException {
// 建立接收端的ServerSocket
ss = new ServerSocket(port);
System.out.println("伺服器啟動!!!");
}
public static void main(String args[]) throws IOException {
new Server().service();
}
private void service() {
// TODO Auto-generated method stub
while (true) {
Socket socket = null;
try {
// 通過accept()方法進行監聽,返回一個socket
socket = ss.accept();
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
package sency.one;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private ServerSocket ss;
private int port = 8000;
public Server() throws IOException {
// 建立接收端的ServerSocket
ss = new ServerSocket(port);
System.out.println("伺服器啟動!!!");
}
public static void main(String args[]) throws IOException {
new Server().service();
}
private void service() {
// TODO Auto-generated method stub
while (true) {
Socket socket = null;
try {
// 通過accept()方法進行監聽,返回一個socket
socket = ss.accept();
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
os.writeUTF("Welcome!");
os.flush();
//輸出客戶端埠
if (socket.isConnected()) {
System.out.println("Port:" + socket.getPort());
}
// 採用多執行緒的方式處理
// 收資訊執行緒
Thread receiveThread = new Thread(new ReHandler(socket));
receiveThread.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// 收資訊
class ReHandler implements Runnable {
private Socket socket = null;
public ReHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
printMsg(socket);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 在伺服器端輸出客戶端傳送的資訊
private void printMsg(Socket socket) throws IOException {
DataInputStream is = new DataInputStream(socket.getInputStream());
String msg = "";
while ((msg = is.readUTF()) != null) {
System.out.println("來自:"+socket.getInetAddress()+"--"+socket.getPort());
System.out.println("#Client:" + msg);
if (msg.equals("bye")) {
break;
}
sendEcho(socket,msg);
}
is.close();
}
// 向客戶端傳送資訊
private void sendEcho(Socket socket,String msg) throws IOException {
if(msg!=null){
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
os.writeUTF("#Server:收到"+msg);
os.flush();
}
}
}
客戶端:
package sency.one;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Client {
private Socket socket;
private String host = "localhost";
private int port = 8000;
public Client() throws IOException {
socket = new Socket(host, port);
System.out.println("客戶端啟動!!!");
System.out.println("Port:"+socket.getLocalPort());
}
public static void main(String args[]) throws IOException {
new Client().talk();
}
private void talk() {
// TODO Auto-generated method stub
// 採用多執行緒分別進行收發資訊
// 傳送執行緒
Thread sendThread = new Thread(new SendHandler());
sendThread.start();
// 收執行緒
Thread reThread = new Thread(new ReHandler());
reThread.start();
}
class SendHandler implements Runnable {
public void run() {
// TODO Auto-generated method stub
try {
sendMsg();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ReHandler implements Runnable {
public void run() {
// TODO Auto-generated method stub
try {
receiveMsg();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//發信息
public void sendMsg() throws IOException {
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
DataInputStream is = new DataInputStream(System.in);
String msg = null;
while ((msg = is.readLine()) != null) {
System.out.println("#Client:" + msg);
os.writeUTF(msg);
os.flush();
if(msg.equals("bye")){
break;
}
}
os.close();
is.close();
}
//收資訊
private void receiveMsg() throws IOException{
DataInputStream is = new DataInputStream(socket.getInputStream());
String msg = null;
while((msg = is.readUTF())!=null){
System.out.println("#Service:"+msg);
if(msg.equals("bye")){
break;
}
}
is.close();
}
}
遇到的問題:
我不知道有沒有人和我一樣在讀寫的時候用了BufferedReader和BufferedWriter,以至於在後面使用readLine()方法時儘管是多執行緒也一直處於阻塞狀態,我找了一下午,後來改成使用DataOutput/InputStream以及對應的readUTF()和writeUTF()方法,這個問題就解決了,具體原因我想了很久也沒想明白,有個猜測不確定,等下週問了老師得到準確的答案再來說吧!!!
立個Flag:接下來有時間的話自己再用nio實現一下非阻塞通訊,到時候來更博!