天行健,君子以自强不息。 ——《周易》
前言:学习内容,略显粗浅。
准备:IDEA打开多个控制台窗口运行程序
目录
- 一、ip地址和端口
- 1.ip地址
- 2.端口
- 3.获取本机IP地址
- 4.ping命令
- 5.使用java 执行ping命令
- 二、Socket
- 1.建立连接
- 2.发送数字
- 3.发送字符串
- 三、多线程聊天
一、ip地址和端口
1.ip地址
在网络中每台计算机都必须有一个的IP地址;
32位,4个字节,常用点分十进制的格式表示,例如:192.168.1.100
127.0.0.1 是固定ip地址,代表当前计算机,相当于面向对象里的 “this”
2.端口
两台计算机进行连接,总有一台服务器,一台客户端。
服务器和客户端之间的通信通过端口进行。
如图:
ip地址是 192.168.1.100的服务器通过端口 8080
与ip地址是192.168.1.189的客户端 的1087端口通信
3.获取本机IP地址
public static void main(String[] args) throws UnknownHostException {
InetAddress host = InetAddress.getLocalHost();
String ip =host.getHostAddress();
System.out.println("本机ip地址:" + ip);
}
4.ping命令
使用ping判断一个地址是否能够到达
ping不是java的api,是windows中的一个小工具,用于判断一个地址的响应时间
如图:
5.使用java 执行ping命令
借助 Runtime.getRuntime().exec() 可以运行一个windows的exe程序
//获取IP
InetAddress host = InetAddress.getLocalHost();
String ip =host.getHostAddress();
System.out.println("本机ip地址:" + ip);
//访问ping
Process p = Runtime.getRuntime().exec("ping "+ ip);
//字符流读取信息
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(),"gbk"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
if (line.length() != 0)
sb.append(line + "\r\n");
}
System.out.println("本次指令返回的消息是:");
System.out.println(sb.toString());
二、Socket
socket是BSD UNIX的通信机制,通常称为“套接字”,其英文原意是“孔”或“插座”。有些顾名思义,socket正如其英文原意一样,像是一个多孔插座,可以提供多个端口的连接服务。
工作原理:
对于服务器来说:服务器先初始化socket,然后端口绑定(bind),再对端口监听(listen),调用accept阻塞,等待客户端连接请求。
对于客户端来说,客户端初始化socket,然后申请连接(connection)。
涉及到TCP三次握手:
- 1.客户端发送连接申请
- 2.服务端收到申请,并回复申请许可
- 3.客户端收到申请许可,并回应自己收到了,然后两边就可以开始发送数据了
1.建立连接
先运行Server,再运行Client
实践代码,搓搓小手动起来(=!=):
服务端Server
package priv.study.network2;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
try {
//服务端打开端口8888
ServerSocket ss = new ServerSocket(8888);
//在8888端口上监听,看是否有连接请求过来
System.out.println("监听在端口号:8888");
Socket s = ss.accept();
System.out.println("有连接过来" + s);
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端Client
package priv.study.network2;
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
//连接到本机的8888端口
try {
Socket s = new Socket("127.0.0.1",8888);
System.out.println(s);
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.发送数字
package priv.study.network2;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server1 {
public static void main(String[] args) {
try {
//服务端打开8888端口
ServerSocket ss = new ServerSocket(8888);
//监听在端口8888
System.out.println("监听在端口号:8888");
Socket s = ss.accept();
//读取客户端发送的消息
InputStream is = s.getInputStream();
int msg = is.read();
System.out.println("客户端来消息了:" +msg );
//用完关闭
is.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package priv.study.network2;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client1 {
public static void main(String[] args) {
try {
//客户端连接端口8888
Socket s = new Socket("127.0.0.1", 8888);
//输出数字100到服务端
OutputStream os = s.getOutputStream();
os.write(100);
//关闭
os.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.发送字符串
直接使用字节流收发字符串比较麻烦,使用数据流对字节流进行封装,这样收发字符串就容易了
- 把输出流封装在DataOutputStream中
使用writeUTF发送字符串 “Legendary!” - 把输入流封装在DataInputStream
使用readUTF读取字符串,并打印
package priv.study.network2;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server2 {
public static void main(String[] args) {
try {
//服务端打开8888端口
ServerSocket ss = new ServerSocket(8888);
//监听在端口8888
System.out.println("监听在端口号:8888");
Socket s = ss.accept();
//读取客户端发送的字符串
//把输入流封装在DataInputStream
InputStream is = s.getInputStream();
DataInputStream dis = new DataInputStream(is);
String msg = dis.readUTF();
System.out.println("客户端来消息了:" +msg );
//用完关闭
dis.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package priv.study.network2;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Client2 {
public static void main(String[] args) {
try {
//客户端连接端口8888
Socket s = new Socket("127.0.0.1", 8888);
//输出字符串到服务端
//把输出流封装在DataOutputStream中
OutputStream os = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
//使用Scanner读取控制台的输入,并发送到服务端
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String str = sc.next();
//使用writeUTF发送字符串
dos.writeUTF(str);
//关闭
dos.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、多线程聊天
如果使用单线程开发Socket应用,那么同一时间,要么收消息,要么发消息,不能同时进行。
为了实现同时收发消息,就需要用到多线程。
这是因为接受和发送都在主线程中,不能同时进行。 为了实现同时收发消息,基本设计思路是把收发分别放在不同的线程中进行
- SendThread 发送消息线程
- RecieveThread 接受消息线程
- Server一旦接受到连接,就启动收发两个线程
- Client 一旦建立了连接,就启动收发两个线程
package priv.study.network2;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class RecieveThread extends Thread{
private Socket s;
public RecieveThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
InputStream is = s.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true) {
String msg = dis.readUTF();
System.out.println(msg);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package priv.study.network2;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class SendThread extends Thread{
private Socket s;
public SendThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
OutputStream os = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
while (true) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
dos.writeUTF(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package priv.study.network2;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server3 {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
System.out.println("监听在端口号:8888");
Socket s = ss.accept();
//启动发送消息线程
new SendThread(s).start();
//启动接受消息线程
new RecieveThread(s).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package priv.study.network2;
import java.io.*;
import java.net.Socket;
public class Client3 {
public static void main(String[] args) {
try {
Socket s = new Socket("127.0.0.1", 8888);
// 启动发送消息线程
new SendThread(s).start();
// 启动接受消息线程
new RecieveThread(s).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
今天学习分享的内容到此为止了,本是想要激励自己学下去,但发现快乐更是知识在于分享!
作为初学者对于Java的理解实在浅薄,如有错误请指正,万分感谢!