900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > Java的TCP/UDP网络编程+多线程实现服务器端与客户端间的通信

Java的TCP/UDP网络编程+多线程实现服务器端与客户端间的通信

时间:2022-10-10 00:13:09

相关推荐

Java的TCP/UDP网络编程+多线程实现服务器端与客户端间的通信

写在前面:

Java为网络编程提供了丰富的库,我们能通过调用Socket套接字的方法实现服务器与客户端的双通信。

注意点:

需要注意的是端口的对应,端口可以理解为窗户,服务器只能通过某个端口(窗户)与外界进行数据通信,客户端也如此。

所以

客户端与服务器端的通信就可以理解为服务器端的一个端口<------>客户端的一个端口 (”<--->“代表是全双工通信,收发信息互不影响)

为什么要用多线程?

因为要想客户端和服务器端互相发数据且互不干扰(以在控制台发数据为例),必须让读取键盘输入流为另一个线程,否则就会一直在等待。

TCP实现客户端与服务器端的通信:

效果:

服务器类:

package com4_18;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import .ServerSocket;import .Socket;import java.util.Scanner;//服务器接受客户端信息class STR implements Runnable {private BufferedReader br;public static boolean sw=false;public STR(BufferedReader bufferedReader) {this.br = bufferedReader;}String mString = null;@Overridepublic void run() {try {if (!sw) {while (!(mString = br.readLine()).equals("bye")) {System.out.println("接受来自客户端的消息:" + mString);}System.out.println("客户端关闭");br.close();}} catch(Exception e){System.out.println("异常");}}}//服务器端给客户端发送数据class STT implements Runnable{private PrintWriter pWriter=null;Scanner in=new Scanner(System.in);public STT(PrintWriter p){this.pWriter=p;}@Overridepublic void run() {while (!STR.sw) {String str = in.nextLine();pWriter.println(str);System.out.println("向客户端发送数据:" + str);if(str.equals("bye"))STR.sw=true;pWriter.flush();}pWriter.close();try {ServerTest.server.close();ServerTest.client.close();} catch (IOException e) {e.printStackTrace();}}}public class ServerTest {private int port=7890;public static ServerSocket server;public static Socket client;public void connect() {//1.构造方法:创建一个服务,并占用一个端口号try {Scanner scanner =new Scanner(System.in);server = new ServerSocket (port);client= server.accept();if (client!=null) {System.out.println("成功连接到客户端");}InputStream is = client.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));OutputStream oStream = client.getOutputStream();PrintWriter pWriter = new PrintWriter(oStream);pWriter.println("你好!客户端,我是服务器端!");pWriter.flush();STR str=new STR(br);Thread thread=new Thread(str);thread.start();STT stt=new STT(pWriter);Thread thread2=new Thread(stt);thread2.start();} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}//端口号一般从1025开始//2.调用accept方法,让服务处于等待状态,并获得Socket// Socket client= server.accept();//3.接收客户端发送的数据//InputStream is = client.getInputStream();//BufferReader//4.向服务器发送数据//OutputStream os = client.getOutputStream(); //PrintWriter//5.server.close(); //网络通信结束后关闭服务}public static void main(String[] args) {// TODO 自动生成的方法存根new ServerTest().connect();}}

客户端类:

package com4_18;import jdk.nashorn.internal.ir.CatchNode;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import .InetAddress;import .Socket;import .UnknownHostException;import java.util.Scanner;import javax.sound.sampled.Port;/*** 客户端从服务器接收数据并打印到控制台上的线程*/class CTR implements Runnable {private BufferedReader br;public static boolean sw=false;public CTR(BufferedReader bufferedReader) {this.br = bufferedReader;}String mString = null;@Overridepublic void run() {try {while (!(mString = br.readLine()).equals("bye")) {System.out.println("客户端接受来自服务器的消息:" + mString);}br.close();System.out.println("服务器端关闭");} catch (Exception e) {System.out.println("异常");}}}/*** 客户端从控制台发送给服务器线程*/class CTT implements Runnable{private PrintWriter pWriter=null;Scanner in=new Scanner(System.in);public CTT(PrintWriter p){this.pWriter=p;}@Overridepublic void run() {while (!CTR.sw) {String str = in.nextLine();pWriter.println(str);System.out.println("客户端向服务器发送数据:" + str);if(str.equals("bye")) CTR.sw=true;pWriter.flush();}pWriter.close();try {ClientTest.client.close();} catch (IOException e) {e.printStackTrace();}}}public class ClientTest {private int port=7890;public static Socket client;public void connect() {Scanner scanner =new Scanner(System.in);//1.与服务器建立连接,如通过IP地址(字符串)和端口构造:try {InetAddress address = InetAddress.getLocalHost();client = new Socket(address,port);if (client!=null) {System.out.println("成功联系到服务器!");}//2.接收服务器发送的数据InputStream is = client.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));OutputStream oStream = client.getOutputStream();PrintWriter pWriter = new PrintWriter(oStream);pWriter.println("你好!服务器,我是客户端!");pWriter.flush();CTT ctt=new CTT(pWriter);Thread thread=new Thread(ctt);thread.start();CTR ctr=new CTR(br);Thread thread1=new Thread(ctr);thread1.start();} catch (UnknownHostException e) {// TODO 自动生成的 catch 块e.printStackTrace();} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}public static void main(String[] args) {// TODO 自动生成的方法存根new ClientTest().connect();}}

UDP客户端与服务器端的通信(和上面的TCP一样,也是通过多线程的方式实现)

与上面的TCP不同的是,我设定服务器端默认给客户端回执信息和接受信息,而上面的TCP则是能通过控制台输入发送给客户端信息。

效果:

与客户端相关类:

客户端接受数据线程类:

package com4_25;import java.io.IOException;import .DatagramPacket;import static com4_25.ClientUDP.datagramSocket;//客户端接受数据包class ClientUDPR extends Thread{//从服务器端接受信息private DatagramPacket datagramPacket;public ClientUDPR() {System.out.println("this is UDPR");}public void run(){while (true) {byte[] buf = new byte[50];datagramPacket = new DatagramPacket(buf, buf.length);try {//接受数据包datagramSocket.receive( datagramPacket);} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}byte[] redata;redata=datagramPacket.getData();String strRecieved = new String(redata);System.out.println("从服务器端:" + datagramPacket.getAddress() +" 的端口:" + datagramPacket.getPort() +"接受到的内容:" + strRecieved);}}}

客户端发送数据线程类:

package com4_25;import java.io.IOException;import .DatagramPacket;import .DatagramSocket;import .InetAddress;import .SocketException;import java.util.Scanner;public class ClientUDP extends Thread {private int port;public static int remotePort;InetAddress serverAdress;public static DatagramSocket datagramSocket = null;private DatagramPacket datagramPacket = null; //包Scanner in = new Scanner(System.in);public ClientUDP(int port, InetAddress serverAdress, int remotePort) {super();this.port = port;this.serverAdress = serverAdress;this.remotePort = remotePort;try {this.datagramSocket = new DatagramSocket(port);} catch (SocketException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}public void run() {while (true) {String sentStr = in.nextLine();//从控制台接受数据byte[] buf;buf = sentStr.getBytes();datagramPacket = new DatagramPacket(buf, buf.length,serverAdress, remotePort);//发送数据包try {datagramSocket.send(datagramPacket);System.out.println("已发送给服务器");} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}}

启动客户端测试类:

package com4_25;import .InetAddress;import .UnknownHostException;public class UDPTest {public static void main(String[] args) {// TODO 自动生成的方法存根InetAddress address;try {address = InetAddress.getLocalHost();new ClientUDP(8080, address, 8001).start();new ClientUDPR().start();} catch (UnknownHostException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}

服务器类:

package com4_25;import .apache.bcel.internal.generic.NEW;import java.io.IOException;import .DatagramPacket;import .DatagramSocket;import .InetAddress;import .SocketException;public class SeverUDP extends Thread {private int port;private DatagramSocket datagramSocket= null;private DatagramPacket datagramPacket= null;public SeverUDP(int port) {super();this.port = port;try {datagramSocket = new DatagramSocket(port);} catch (SocketException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}public void run() {if (datagramSocket==null) {System.out.println("没有成功创建服务器!");}while (true) {try {/*** 服务器从客户端接受消息*/byte[]buf =new byte[50];datagramPacket = new DatagramPacket(buf,buf.length );datagramSocket.receive(datagramPacket);InetAddress address = datagramPacket.getAddress();int remotePort = datagramPacket.getPort();buf = datagramPacket.getData();String recievedData = new String(buf);System.out.println("从地址:"+address+"端口:(客户端)"+remotePort+"内容:" );char []mystr=recievedData.toCharArray();for (int i = 0; i <mystr.length; i++) {if(mystr[i]==' ')break;System.out.print(mystr[i]);}String sendStr = "服务器的回执(表示服务器已经收到)";/*** 回敬给客户端消息*/buf = sendStr.getBytes();System.out.println(new String(buf));datagramPacket = new DatagramPacket(buf, buf.length, address, remotePort);datagramSocket.send(datagramPacket);} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}public static void main(String[] args) {// TODO 自动生成的方法存根new SeverUDP(8001).start();}}

值得注意的是:TCP服务器与客户端的通信需要建立连接,而UDP服务器与客户端的通信则是以接受数据包SocketPackage的形式获取报文,而报文的长度一开始再创建Socketpacket时又无从得知。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。