【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序
- 結合多線程實現socket
- 使用非線程池(拓展Thread)
- 使用線程池(Executor pool)
- 使用DatagramPacket DatagramSocket開發UDP/IP程序
- 使用UDP獲取服務端時間
- 其他
- 使用socket類作為客戶端鏈接網站:
- 用ServerSocket創建一個web服務器:
首先:accept()和Read()方法都有阻塞特性
結合多線程實現socket
在Socket技術中,常用的實踐方式就是Socket結合Thread多線程技術,客戶端每發起一次新的請求,就把這個請求交給新創建的線程來執行這次業務。當然,如果使用線程池技術,則會更加高效。本示例先使用原始的非線程池來進行演示。
//socket類提供了兩個方法用于得到輸入流和輸出流,分別是getInputStream()和getOutputStream() 可以對其進行包裝
//例如:Socket socket = new Socket(“localhost”,8189);
// PrintStream oStream = new PrintStream( new BufferedOutputStream(socket.getOutputStream()));
//DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
一個使用DataInputStream的簡單例子:
使用非線程池(拓展Thread)
beginthread:
//多線程實現socket public class BeginThread extends Thread{private Socket socket;public BeginThread(Socket socket){super();this.socket = socket;}@Overridepublic void run(){try{InputStream inputStream = socket.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream);char[] charArr = new char[1000];int readLen = -1;while((readLen = (inputStreamReader.read(charArr))) != -1){String newString = new String(charArr,0,readLen);System.out.println(newString);}inputStreamReader.close();inputStream.close();//關閉兩個流socket.close();//關閉socket}catch (IOException e){e.printStackTrace();}} }beginserver類:
public class BeginServer {public static void main(String[]args) throws IOException {ServerSocket socket = new ServerSocket(8888);int runTag = 1;while (runTag == 1){Socket socket1 = socket.accept();BeginThread beginThread = new BeginThread(socket1);beginThread.start();}socket.close();} }BeginClient :
public class BeginClient {public static void main(String[]args) throws IOException {Socket socket = new Socket("localhost",8888);OutputStream outputStream = socket.getOutputStream(); // OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); // outputStreamWriter.write(String.valueOf("我是中國人".getBytes(StandardCharsets.UTF_8)));outputStream.write("我是中國人yaoo".getBytes(StandardCharsets.UTF_8));outputStream.close();socket.close();} }客戶端每次發完一條數據就會關閉連接,而服務端一直會有線程接收請求。修改客戶端的字符串,服務端結果:
由于 Socket socket1 = socket.accept();的阻塞特性,只有服務端受到客戶端的信號之后才會開啟一個新的線程。
使用線程池(Executor pool)
將以上代碼修改為使用線程池:
beginThread只需要修改為
implements Runnable
而beginServer改為:
結果是一樣的。
使用DatagramPacket DatagramSocket開發UDP/IP程序
DatagramPacket DatagramSocket是用來支持數據報通信的兩個類,前者由于表示數據報,后者用于建立通信連接
寫改程序首先需要建立一個DatagramSocket對象,用來接收或者發送數據報,然后以DatagramPacket 作為數據傳輸的載體。
使用UDP獲取服務端時間
client:
public class UdpClient {public void go() throws IOException, UnknownHostException{DatagramPacket ingramPacket;DatagramPacket outgramPacket;DatagramSocket datagramSocket;InetAddress serverAdress;byte[]msg = new byte[100];//緩沖區String receivedmsg;datagramSocket = new DatagramSocket();System.out.println("an udpclient ,datagramsocket:"+datagramSocket.getPort()+"localport:"+datagramSocket.getLocalPort());serverAdress = InetAddress.getLocalHost();outgramPacket = new DatagramPacket(msg,1,serverAdress,8000);//send to port 8000datagramSocket.send(outgramPacket);//make the request to the serveringramPacket = new DatagramPacket(msg,msg.length);//set up a datagram packet to receive server's responsedatagramSocket.receive(ingramPacket);receivedmsg = new String(ingramPacket.getData(),0,ingramPacket.getLength());System.out.println(receivedmsg);//print the data received from the serverdatagramSocket.close();}public static void main(String[]args) throws IOException {UdpClient udpClient = new UdpClient();try {udpClient.go();}catch (Exception e){System.out.println(e);}} }server:
public class UdpServer {public byte[]getTime(){Date d = new Date();return d.toString().getBytes(StandardCharsets.UTF_8); } public void go() throws IOException{DatagramPacket inDataPacket;DatagramPacket outDataPacket;DatagramSocket datagramSocket;InetAddress clientAdress;int clientPort;byte[]msg = new byte[10];//Incoming data buffer.ignoredbyte[]time;datagramSocket = new DatagramSocket(8000);//allocate a socket to man port 8000 for requestsSystem.out.println("UDPserver :"+datagramSocket.getPort()+"local is:"+datagramSocket.getLocalPort());System.out.println("udpserver active on port 8000");while (true){inDataPacket = new DatagramPacket(msg,msg.length);datagramSocket.receive(inDataPacket);//get the messageclientAdress = inDataPacket.getAddress();clientPort = inDataPacket.getPort();time=getTime();outDataPacket = new DatagramPacket(time,time.length,clientAdress,clientPort);datagramSocket.send(outDataPacket);//send the packet} }public static void main(String[]args){UdpServer udpServer = new UdpServer();try{udpServer.go();}catch (IOException e){e.printStackTrace();}}}結果:
客戶端接收一次數據之后即關閉連接,而服務端一直可以接收請求。
其他
使用socket類作為客戶端鏈接網站:
public class Hzy {public static void main(String args[]) throws IOException {Socket socket = null;try {socket = new Socket("www.csdn.net", 80);System.out.println("socket連接成功");} catch (IOException e) {System.out.println("socket連接失敗");e.printStackTrace();} finally {socket.close();} }}
注意:如果host為不存在的域名,會發生報錯
用ServerSocket創建一個web服務器:
public class Hzy {public static void main(String args[]) throws IOException {ServerSocket serverSocket = new ServerSocket(6666,1, InetAddress.getByName("127.0.0.1"));Socket socket = serverSocket.accept();InputStream inputStream = socket.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String getString = "";while (!"".equals(getString = bufferedReader.readLine())) {System.out.println(getString);}OutputStream outputStream = socket.getOutputStream();outputStream.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());outputStream.write("<html><body><a href='http://www.baidu.com'>i am baidu.com welcome you!</a></body></html>".getBytes());outputStream.flush();inputStream.close();outputStream.close();socket.close();serverSocket.close();}}這個代碼不知道為什么打開瀏覽器還是沒法訪問,原因還未找到。
文件目錄:
chartserver:
ServerThread
public class ServerThread implements Runnable {private SocketBean mSocket = null;private BufferedReader mReader = null;public ServerThread(SocketBean mSocket) throws IOException {this.mSocket = mSocket;mReader = new BufferedReader(new InputStreamReader(mSocket.socket.getInputStream()));}@Overridepublic void run() {try {String content = null;// 循環不斷地從Socket中讀取客戶端發送過來的數據while ((content = mReader.readLine()) != null) {System.out.println("content="+content);int pos = content.indexOf("|");// 包頭格式為:動作名稱|設備編號|昵稱|時間|對方設備編號String head = content.substring(0, pos);String body = content.substring(pos+1);String[] splitArray = head.split(",");String action = splitArray[0];System.out.println("action="+action);if (action.equals("LOGIN")) {login(splitArray[1], splitArray[2], splitArray[3]);} else if (action.equals("LOGOUT")) {logout(splitArray[1]);break;} else if (action.equals("SENDMSG")) {sendmsg("RECVMSG", splitArray[2], splitArray[4], splitArray[1], body);} else if (action.equals("GETLIST")) {getlist(splitArray[1]);} else if (action.equals("SENDPHOTO")) {sendmsg("RECVPHOTO", splitArray[2], splitArray[4], splitArray[1], body);} else if (action.equals("SENDSOUND")) {sendmsg("RECVSOUND", splitArray[2], splitArray[4], splitArray[1], body);}}} catch (Exception e) {e.printStackTrace();}}private void login(String deviceId, String nickName, String loginTime) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.id.equals(mSocket.id)) {item.deviceId = deviceId;item.nickName = nickName;item.loginTime = loginTime;ChatServer.mSocketList.set(i, item);break;}}}private String getFriend() {String friends = "GETLIST,";for (SocketBean item : ChatServer.mSocketList) {if (item.deviceId!=null && item.deviceId.length()>0) {String friend = String.format("|%s,%s,%s", item.deviceId, item.nickName, item.loginTime);friends += friend;}}return friends;}private void getlist(String deviceId) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {PrintStream ps = new PrintStream(item.socket.getOutputStream());ps.println(getFriend());break;}}}private void logout(String deviceId) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {PrintStream ps = new PrintStream(item.socket.getOutputStream());ps.println("LOGOUT,|");item.socket.close();ChatServer.mSocketList.remove(i);break;}}}private void sendmsg(String respAction, String otherName, String otherId, String selfId, String message) throws IOException {for (int i=0; i<ChatServer.mSocketList.size(); i++) {SocketBean item = ChatServer.mSocketList.get(i);if (item.deviceId.equals(otherId)) {String content = String.format("%s,%s,%s,%s|%s", respAction, selfId, otherName, DateUtil.getNowTime(), message);System.out.println("resp="+content);PrintStream ps = new PrintStream(item.socket.getOutputStream());ps.println(content);break;}}}}socketbean:
public class SocketBean {public String id;public Socket socket;public String deviceId;public String nickName;public String loginTime;public SocketBean(String id, Socket socket) {this.id = id;this.socket = socket;this.deviceId = "";this.nickName = "";this.loginTime = "";}}TestServer:
public class TestServer {private static final int SOCKET_PORT = 51000;private void initServer() {try {// 創建一個ServerSocket,用于監聽客戶端Socket的連接請求ServerSocket server = new ServerSocket(SOCKET_PORT);while (true) {Socket socket = server.accept();new Thread(new ServerThread(socket)).start();}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {TestServer server = new TestServer();server.initServer();}private class ServerThread implements Runnable {private Socket mSocket;private BufferedReader mReader;public ServerThread(Socket socket) throws IOException {mSocket = socket;mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));}@Overridepublic void run() {try {String content = null;// 循環不斷地從Socket中讀取客戶端發送過來的數據while ((content = mReader.readLine()) != null) {System.out.println("收到客戶端消息:"+content);PrintStream ps = new PrintStream(mSocket.getOutputStream());ps.println("hi,很高興認識你");}} catch (Exception e) {e.printStackTrace();}}}}客戶端:
public class MessageTransmit implements Runnable {private static final String TAG = "MessageTransmit";// 以下為Socket服務器的ip和端口,根據實際情況修改private static final String SOCKET_IP = "192.168.0.212";private static final int SOCKET_PORT = 51000;private Socket mSocket;private BufferedReader mReader = null;private OutputStream mWriter = null;@Overridepublic void run() {mSocket = new Socket();try {mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));mWriter = mSocket.getOutputStream();// 啟動一條子線程來讀取服務器的返回數據new RecvThread().start();Looper.prepare();Looper.loop();} catch (Exception e) {e.printStackTrace();}}// 定義接收UI線程的Handler對象,App向后臺服務器發送消息public Handler mRecvHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {Log.d(TAG, "handleMessage: "+msg.obj);// 換行符相當于回車鍵,表示我寫好了發出去吧String send_msg = msg.obj.toString()+"\n";try {mWriter.write(send_msg.getBytes("utf8"));} catch (Exception e) {e.printStackTrace();}}};// 定義消息接收子線程,App從后臺服務器接收消息private class RecvThread extends Thread {@Overridepublic void run() {try {String content = null;while ((content = mReader.readLine()) != null) {// 讀取到來自服務器的數據Message msg = Message.obtain();msg.obj = content;SocketActivity.mHandler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();}}}} public class ClientThread implements Runnable {private static final String TAG = "ClientThread";private static final String SOCKET_IP = "192.168.253.1";//private static final String SOCKET_IP = "192.168.0.212";private static final int SOCKET_PORT = 52000;public static final String REQUEST_URL = "http://192.168.253.1:8080/UploadTest";private Context mContext;private Socket mSocket;public Handler mRecvHandler;private BufferedReader mReader = null;private OutputStream mWriter = null;public static String ACTION_RECV_MSG = "com.example.network.RECV_MSG";public static String ACTION_GET_LIST = "com.example.network.GET_LIST";public static String CONTENT = "CONTENT";public static String SPLIT_LINE = "|";public static String SPLIT_ITEM = ",";public static String LOGIN = "LOGIN";public static String LOGOUT = "LOGOUT";public static String SENDMSG = "SENDMSG";public static String RECVMSG = "RECVMSG";public static String GETLIST = "GETLIST";public static String SENDPHOTO = "SENDPHOTO";public static String RECVPHOTO = "RECVPHOTO";public static String SENDSOUND = "SENDSOUND";public static String RECVSOUND = "RECVSOUND";public ClientThread(Context context) {mContext = context;}@Overridepublic void run() {Log.d(TAG, "run");mSocket = new Socket();try {Log.d(TAG, "connect");mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));Log.d(TAG, "getOutputStream");mWriter = mSocket.getOutputStream();Log.d(TAG, "RecvThread");// 啟動一條子線程來讀取服務器相應的數據new RecvThread().start();Looper.prepare();// 定義接收UI線程的Handler對象,App向后臺服務器發送消息// 如果是在Application中啟動線程,則mRecvHandler要在線程啟動后才能初始化// 并且要在Looper.prepare之后執行初始化動作mRecvHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// 接收到UI線程的用戶輸入的數據try {mWriter.write(msg.obj.toString().getBytes("utf8"));} catch (Exception e) {e.printStackTrace();}}};Looper.loop();} catch (Exception e) {e.printStackTrace();notify(99, e.getMessage());}}// 定義消息接收子線程,App從后臺服務器接收消息private class RecvThread extends Thread {@Overridepublic void run() {String content = null;try {while ((content = mReader.readLine()) != null) {// 讀取到來自服務器的數據之后,發送消息通知ClientThread.this.notify(0, content);}} catch (Exception e) {e.printStackTrace();ClientThread.this.notify(97, e.getMessage());}}}private void notify(int type, String message) {if (type == 99) {String content = String.format("%s%s%s%s", "ERROR", SPLIT_ITEM, SPLIT_LINE, message);Intent intent1 = new Intent(ACTION_RECV_MSG);intent1.putExtra(CONTENT, content);mContext.sendBroadcast(intent1);Intent intent2 = new Intent(ACTION_GET_LIST);intent2.putExtra(CONTENT, content);mContext.sendBroadcast(intent2);} else {int pos = message.indexOf(SPLIT_LINE);String head = message.substring(0, pos - 1);String[] splitArray = head.split(SPLIT_ITEM);String action = "";if (splitArray[0].equals(RECVMSG) || splitArray[0].equals(RECVPHOTO) || splitArray[0].equals(RECVSOUND)) {action = ACTION_RECV_MSG;} else if (splitArray[0].equals(GETLIST)) {action = ACTION_GET_LIST;}Log.d(TAG, "action=" + action + ", message=" + message);Intent intent = new Intent(action);intent.putExtra(CONTENT, message);mContext.sendBroadcast(intent);}}}總結
以上是生活随笔為你收集整理的【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【学习笔记】springboot的过滤器
- 下一篇: UnhandledPromiseReje