网络通信三要素:IP, 端口 , 协议: UDP TCP
端口:逻辑端口 他的范围 0–65535 其中0-1023被系统所占用,你要用的时候,就不要用别人用过的。
针对IP Java提供了一个类用来描述
tatic InetAddress getByName (String host):在给定主机名的情况下确定主机的 IP 地址。
hostname 这个命令,可以查看主机名
InetAddress inetAddress = InetAddress.getByName("Lenovo-PC");
//获取IP
String ip = inetAddress.getHostAddress();
System.out.println(ip);
//获取主机名
String hostName = inetAddress.getHostName();
System.out.println(hostName);
System.out.println("============================");
//传入IP也可以
InetAddress inetAddress2 = InetAddress.getByName("192.168.31.136");
String hostAddress = inetAddress2.getHostAddress();
String hostName1 = inetAddress2.getHostName();
System.out.println(hostAddress);
System.out.println(hostName1);
}
}
Socket=IP+端端口 也叫做套接字编程。要求通信两端都要有这个Socket,针对不同协议的Socket Java给我们提供了相应的Socket。
UDP协议的特点:通信两端不需要建立连接,发送的数据大小有限制,因为不需要建立连接,效率高一些,但是属于不可靠协议,有肯会发生数据丢失问题。
UDP协议的Socket: DatagramSocket 此类表示用来发送和接收数据报包的套接字。UDP协议的Socket 客户端和服务端用的都是一个类DatagramSocket。
public class fasong {
public static void main (String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket ();
byte[] bytes = "发送".getBytes ();
类 DatagramPacket 此类表示数据报包。
/* DatagramPacket( byte[] buf, int length, InetAddress address,int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。*/
//数据报包里面封装:你要发送的数据,数据的长度,对方的IP 对方的端口
DatagramPacket packet = new DatagramPacket (bytes,bytes.length, InetAddress.getByName ("192.168.31.136"),8888);
datagramSocket.send (packet);//发送数据报包
datagramSocket.close ();//关闭资源
}
}
public class jieshou {
public static void main (String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket (8888);//暴露端口号
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket (bytes, bytes.length);
socket.receive (datagramPacket); //接收发送的数据,他需要一个空的数据报包,用来装发过来的数据
byte[] data = datagramPacket.getData ();//获取数据包里面的数据
int length = datagramPacket.getLength ();//获取数据的长度
int port = datagramPacket.getPort ();//取对方端口
String s = new String (data, 0, length);//转换成字符串
InetAddress address = datagramPacket.getAddress ();//获取对方IP地址
String hostAddress = address.getHostAddress ();//对方IP地址
System.out.println ("IP:"+hostAddress+"端口:"+port+"发送的消息:"+s);
socket.close ();
}
}
DatagramSocket( int port)
创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramPacket( byte[] buf, int length)
构造 DatagramPacket,用来接收长度为 length 的数据包
用线程来做的话:
public class A extends Thread{
@Override
public void run () {
try {
DatagramSocket datagramSocket = new DatagramSocket ();
BufferedReader reader = new BufferedReader (new InputStreamReader (System.in));
while (true){
System.out.println ("请输入");
String s = reader.readLine ();
byte[] bytes = s.getBytes ();
int length = bytes.length;
DatagramPacket packet = new DatagramPacket (bytes,length, InetAddress.getByName ("192.168.31.136"),3848);
datagramSocket.send (packet);
if( "溜了".equals (s)){
break;
}
}
datagramSocket.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
public class B extends Thread{
@Override
public void run () {
try {
DatagramSocket datagramSocket = new DatagramSocket (3848);
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket (bytes,bytes.length);
System.out.println ("信息传入中");
while (true){
datagramSocket.receive (datagramPacket);
int length = datagramPacket.getLength ();
String hostAddress = datagramPacket.getAddress ().getHostAddress ();
int port = datagramPacket.getPort ();
String s = new String (bytes, 0, length);
System.out.println ("IP:"+hostAddress+"端口:"+port+"信息:"+s);
if("溜了".equals (s)){
break;
}
}
datagramSocket.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
A与B之间相互传输信息:
public class A {
public static void main (String[] args) throws Exception {
new Thread (new Runnable () {
@Override
public void run () {
try {
DatagramSocket datagramSocket = new DatagramSocket (1234);
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket (bytes, bytes.length);
System.out.println ("A平台准备就绪,B平台信号传入中。。。");
while (true){
datagramSocket.receive (datagramPacket);
byte[] data = datagramPacket.getData ();
int length = datagramPacket.getLength ();
String s = new String (bytes, 0, length);
int port = datagramPacket.getPort ();
String hostAddress = datagramPacket.getAddress ().getHostAddress ();
System.out.println ("IP:"+hostAddress+"端口:"+port+"信息:"+s);
}
} catch (IOException e) {
e.printStackTrace ();
}
}
}).start();
//以上是接受B的信息
sendfasong();
}
private static void sendfasong() throws Exception{
DatagramSocket datagramSocket = new DatagramSocket();
BufferedReader reader = new BufferedReader (new InputStreamReader (System.in));
while (true) {
System.out.println("请输入你要发送给B的消息");
String msg = reader.readLine();
if ("886".equals(msg)) {
break;
}
byte[] bytes = msg.getBytes();
int length = bytes.length;
DatagramPacket datagramPacket = new DatagramPacket(bytes, length, InetAddress.getByName("192.168.31.136"), 8888);
datagramSocket.send(datagramPacket);
}
//释放资源
datagramSocket.close();
}
}
//这段为发送到B的信息块
public class B {
public static void main (String[] args) throws Exception {
new Thread (new Runnable () {
@Override
public void run () {
try {
DatagramSocket datagramSocket = new DatagramSocket (8888);
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket (bytes, bytes.length);
System.out.println ("A平台准备就绪,B平台信号传入中。。。");
while (true){
datagramSocket.receive (datagramPacket);
byte[] data = datagramPacket.getData ();
int length = datagramPacket.getLength ();
String s = new String (bytes, 0, length);
int port = datagramPacket.getPort ();
String hostAddress = datagramPacket.getAddress ().getHostAddress ();
System.out.println ("IP:"+hostAddress+"端口:"+port+"信息:"+s);
}
} catch (IOException e) {
e.printStackTrace ();
}
}
}).start();
sendfasong();
}
private static void sendfasong() throws Exception{
DatagramSocket datagramSocket = new DatagramSocket();
BufferedReader reader = new BufferedReader (new InputStreamReader (System.in));
while (true) {
System.out.println("请输入你要发送给B的消息");
String msg = reader.readLine();
if ("886".equals(msg)) {
break;
}
byte[] bytes = msg.getBytes();
int length = bytes.length;
DatagramPacket datagramPacket = new DatagramPacket(bytes, length, InetAddress.getByName("192.168.31.136"), 1234);
datagramSocket.send(datagramPacket);
}
datagramSocket.close();
}
}
TCP:通信两段需要建立连接,形成数据传输的通道,属于可靠协议,传输大小无限制。
TCP的客户端套接字:Socket。套接字是两个机器之间的通信的端点。
Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号
public class fasong {
public static void main (String[] args) throws IOException {
Socket socket = new Socket ("192.168.31.136",8848);/指定IP与端口
OutputStream outputStream = socket.getOutputStream ();//获取通信道的输出流
outputStream.write ("指令发送".getBytes ());
socket.close ();
}
}
public class jieshou {
public static void main (String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket (8848);
Socket accept = serverSocket.accept ();// //阻塞式方法,侦听客户端的连接
InputStream inputStream = accept.getInputStream ();//获取数据
byte[] bytes = new byte[1024];
int read = inputStream.read (bytes);
String s = new String (bytes,0,read);//转换成字符串
String hostAddress = serverSocket.getInetAddress ().getHostAddress ();
System.out.println ("ip:"+hostAddress+"信息:"+s);
serverSocket.close ();
}
}
ServerSocket 此类实现服务器套接字。
ServerSocket( int port)
创建绑定到特定端口的服务器套接字。并暴露端口号
//java.net.BindException:Address already in use:JVM_Bind 端口被占用的异常
//java.net.BindException:Address already in use:JVM_Bind 端口被占用的异常
案例:
客户端发送数据,服务器接受数据并给出反馈
public class fasong {
public static void main (String[] args) throws IOException {
Socket socket = new Socket ("192.168.31.136",8848);
OutputStream outputStream = socket.getOutputStream ();
outputStream.write ("指令发送".getBytes ());
InputStream inputStream = socket.getInputStream ();
byte[] bytes = new byte[1024];
int read = inputStream.read (bytes);
String s = new String (bytes,0,read);
System.out.println (s);
socket.close ();
}
}
public class jieshou {
public static void main (String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket (8848);
Socket accept = serverSocket.accept ();
InputStream inputStream = accept.getInputStream ();
byte[] bytes = new byte[1024];
int read = inputStream.read (bytes);
String s = new String (bytes,0,read);
OutputStream outputStream = accept.getOutputStream ();
outputStream.write ("请求接受".getBytes ());
String hostAddress = serverSocket.getInetAddress ().getHostAddress ();
System.out.println ("ip:"+hostAddress+"信息:"+s);
serverSocket.close ();
}
}
案例:
客户端键盘录入服务器控制台输出
public class kehuduan {
public static void main (String[] args) throws IOException {
Socket socket = new Socket ("192.168.31.136",8848);
OutputStream outputStream = socket.getOutputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader (System.in));
BufferedWriter writer = new BufferedWriter (new OutputStreamWriter (outputStream));
while (true){
System.out.println ("请输入");
String s = reader.readLine ();
if ("溜了".equals (s)){
break;
}
writer.write (s);
writer.newLine ();
writer.flush ();
}
outputStream.close ();
}
}
public class server {
public static void main (String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket (8848);
Socket accept = serverSocket.accept ();
InputStream inputStream = accept.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader (inputStream));
BufferedWriter writer = new BufferedWriter (new FileWriter ("123.txt"));
String s=null;
while ((s=reader.readLine ())!=null){
System.out.println (s);
}
}
}
案例:
客户端读取文本文件服务器控制台输出
public class MyClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.31.136", 9999);
OutputStream out = socket.getOutputStream();
//你可以把通道中的字节流,包装成字符流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
//创建输入流来读取文本文件
BufferedReader reader = new BufferedReader(new FileReader("LHC.java"));
String line=null;
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine();
writer.flush();
}
socket.close();
reader.close();
}
}
public class MyServer {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9999);
System.out.println("服务端已经开启,等待连接。。。。。");
Socket sk = ss.accept();
InputStream in = sk.getInputStream();
//把通道中的字节流,包装成字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String s =null;
while ((s=reader.readLine())!=null){
System.out.println(s);
}
}
}
TCP协议上传文本文件
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.31.136", 5555);
//获取通道中的输入流,输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
BufferedReader reader= new BufferedReader(new FileReader("LHC.java"));
String line=null;
//包装通道中的输出流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine();
writer.flush();
}
//释放资源
socket.close();
reader.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(5555);
System.out.println("服务器已经开启等待连接。。。。。");
Socket socket = serverSocket.accept();
//获取通道中的输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
//包装通道中的输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
BufferedWriter writer = new BufferedWriter(new FileWriter("xiazai.java"));
String line=null;
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine();
writer.flush();
}
serverSocket.close();
writer.close();
}
}
TCP上传文本文件并给出反馈
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.31.136", 5555);
//获取通道中的输入流,输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
BufferedReader reader= new BufferedReader(new FileReader("TCPClient.java"));
String line=null;
//包装通道中的输出流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine();
writer.flush();
}
writer.write("over");
writer.newLine();
writer.flush();
//读取服务端的反馈
byte[] bytes = new byte[1024];
int len = in.read(bytes); //读取服务端的反馈,读取不到,就阻塞在这里
System.out.println(new String(bytes,0,len));
//释放资源
socket.close();
reader.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(5555);
System.out.println("服务器已经开启等待连接。。。。。");
Socket socket = serverSocket.accept();
//获取通道中的输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
//包装通道中的输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
BufferedWriter writer = new BufferedWriter(new FileWriter("upload2.java"));
String line=null;
while ((line=reader.readLine())!=null){
//如果读取到客户端写过来的一个标记,我就结束这个循环。
if ("over".equals(line)) {
break;
}
writer.write(line);
writer.newLine();
writer.flush();
}
//如果上传成功,服务端给客户端一个反馈
out.write("上传服务器成功".getBytes());
System.out.println("服务端下来了");
serverSocket.close();
writer.close();
}
}
但是此处的“over”自定义结束符存在:如果文本中途出现“over”,那么势必会导致文本传出不全。
public class TCPClient {
public static void main(String[] args) throws IOException {
//上传文本文件
Socket socket = new Socket("192.168.47.1", 5555);
//获取通道中的输入流,输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
BufferedReader reader= new BufferedReader(new FileReader("TCPClient.java"));
String line=null;
//包装通道中的输出流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine();
writer.flush();
}
//可以用另一个方案,可户端传完之后,把通道中的是输出流关掉,服务端那边就不会在等待了。
socket.shutdownOutput();
//读取服务端的反馈
byte[] bytes = new byte[1024];
int len = in.read(bytes); //读取服务端的反馈,读取不到,就阻塞在这里
System.out.println(new String(bytes,0,len));
//释放资源
socket.close();
reader.close();
}
}
多线程改进上传文本文件
public class TCPServer {
public static void main(String[] args) throws IOException {
//让一个服务端。连接多个客户端。
ServerSocket serverSocket = new ServerSocket(5555);
System.out.println("服务器已经开启等待连接。。。。。");
int i=1;
while (true){
//循环侦听客户端
Socket socket = serverSocket.accept();
System.out.println((i++)+"个客户端连接上来了");
//为每一个连接上来的客户端,单独开启一个线程来处理
//把每个客户端socket 传入到线程里面去
new UpLoadThread(socket).start();
}
}
}