java回顾之Socket网络编程
java回顾之Socket网络编程
一、软件结构
C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件
特点:
优点:
对网络要求不是很高
缺点:
开发维护周期长
占用空间
B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等
特点
优点:
开发维护周期短
不占用空间
缺点:
对网络网速要求高
二、网络编程三要素
ip地址:
ip地址是计算机的唯一标识。互联网上面的每个设备都有唯一的ip地址
查ip的命令:ipconfig
ip的分类
IPV4:有4个255的段落,192.168.31.56。IPV4已经被全世界的设备用光了
IPV6: ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 ,号称能给世界的每一粒沙子分配一个不重复的IP
端口号:
端口号是软件的唯一标识。每个软件都有一个唯一的端口号,范围是0~65535,其中0~1023是留给系统使用的要 避开。
协议:
协议是传输数据的方式
TCP:面向连接,安全,效率低
三次握手
UDP:面向无连接,不安全,效率高,对数据包有大小限制不能超过64K
三、InetAddress类
InetAddress类成员方法
* static InetAddress getLocalHost()
获得本地主机IP地址对象
* static InetAddress getByName(String host)
根据IP地址字符串或主机名获得对应的IP地址对象
* String getHostName() 获得主机名
* String getHostAddress() 获得IP地址字符串
四、TCP通信程序

代码演示:
客户端发送数据
public class Demo客户端 {
public static void main(String[] args) throws IOException {
//创建套接字对象
//客户端要指定给谁发送数据
//第一个参数是对方的ip 第二个参数是对方的端口
Socket s = new Socket("192.168.31.87",8888);
//Socket里面包含输出流和输入流,我们网络编程需要获取底层流完成数据发送
//获取输出流
OutputStream os = s.getOutputStream();
//键盘输入内容发送
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
//输出(把字符串转成字节数组)
os.write(str.getBytes());
//关闭资源
s.close();
}
}
服务端接收数据
public class Demo服务器端 {
public static void main(String[] args) throws IOException {
//创建服务器对象
//参数代表的是自己的端口
ServerSocket ss = new ServerSocket(8888);
//接受客户单的连接
//阻塞(如果连接不到客户端就会一直等待)
Socket s = ss.accept();
//获取输入流
InputStream is = s.getInputStream();
//接受数据
byte[] arr = new byte[1024];
//默认发送的时候就只发了一句话,不需要使用循环读取
int len = is.read(arr);
//打印
System.out.println("客户端对我说:" + new String(arr,0,len));
//关闭资源
s.close();
//ss.close();服务器打开之后一般不会关闭
}
}
4.3、TCP模拟聊天
客户端代码
public class Demo客户端 {
public static void main(String[] args) throws IOException {
//创建套接字对象
//客户端要指定给谁发送数据
//第一个参数是对方的ip 第二个参数是对方的端口
Socket s = new Socket("192.168.31.87",9999);
//Socket里面包含输出流和输入流,我们网络编程需要获取底层流完成数据发送
while(true) {
//获取输出流
OutputStream os = s.getOutputStream();
//键盘输入内容发送
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
//输出(把字符串转成字节数组)
os.write(str.getBytes());
//接受数据
//获取输入流
InputStream is = s.getInputStream();
byte[] arr = new byte[1024];
//读取内容
int len = is.read(arr);
//打印
System.out.println("服务器对我说: " + new String(arr, 0, len));
}
//关闭资源
//s.close();
}
}
服务端代码:
public class Demo服务器端 {
public static void main(String[] args) throws IOException {
//创建服务器对象
//参数代表的是自己的端口
ServerSocket ss = new ServerSocket(9999);
//接受客户单的连接
Socket s = ss.accept(); //阻塞(如果连接不到客户端就会一直等待)
while(true) {
//获取输入流
InputStream is = s.getInputStream();
//接受数据
byte[] arr = new byte[1024];
//默认发送的时候就只发了一句话,不需要使用循环读取
int len = is.read(arr);
//打印
System.out.println("客户端对我说:" + new String(arr, 0, len));
//发送数据
//获取输出流
OutputStream os = s.getOutputStream();
//发送固定语句
os.write("滚".getBytes());
}
//关闭资源
//s.close();
//ss.close();服务器打开之后一般不会关闭
}
}
4.4、文件上传案例

客户端发送文件
public class Demo文件上传的客户端 {
public static void main(String[] args) throws IOException {
//创建对象
//Socket s = new Socket("127.0.0.1",5678);
//Socket s = new Socket("localhost",5678);
Socket s = new Socket("192.168.31.87",5678);
//创建输入流
FileInputStream fis = new FileInputStream("C:\\资料\\小资料\\微信图片_20190108110420.jpg");
//获取输出流
OutputStream os = s.getOutputStream();
//每次读取一个字节发送给服务器
int i;
while((i = fis.read()) != -1){
//输出
os.write(i);
}
//关闭资源
fis.close();
s.close();
}
}
服务器接收文件
public class Demo文件上传的服务器端 {
public static void main(String[] args) throws IOException {
//创建对象
ServerSocket ss = new ServerSocket(5678);
//获取客户端连接
Socket s = ss.accept();
//获取输入流
InputStream is = s.getInputStream();
//创建输出流
FileOutputStream fos = new FileOutputStream("day18\\上传图片.jpg");
//每次读取一个字节输出一个字节
int i;
while ((i=is.read()) != -1){
fos.write(i);
}
//关流
fos.close();
s.close();
}
}
有个循环发送的问题。

解决办法:
-
客户端停止发送数据之后,需要通知服务器:
s.shutdownOutput();
4.6、
B/S模式是web的内容,以下是服务器需要给浏览器发送的响应信息,在正式传输数据前,要先写这个。
-
```
发送图片:
"HTTP/1.1 200 OK\r\nContent-Type:image/jpeg\r\n\r\n"
发送文字时:
"HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=UTF-8\r\n\r\n"
```
- 服务器端
public class Demo服务器 {
public static void main(String[] args) {
try {
//创建服务器对象
ServerSocket ss = new ServerSocket(7890);
while (true) {
//接受浏览器的请求
Socket s = ss.accept();
//获取输入流
InputStream is = s.getInputStream();
//调用读取一行字符串的方法
//readLine()
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = br.readLine();
//从浏览器发过来的数据
//System.out.println(str); // GET /1.jpg HTTP/1.1
//1.截取用户要访问的资源名称
String[] arr = str.split(" ");
String name = arr[1]; // /1.jpg
//2.查找文件是否存在
File f = new File("day18/发车" + name); //路径: day18/发车/4.jpg
//3.获取输出流
BufferedOutputStream os = new BufferedOutputStream(s.getOutputStream());
if (f.exists()) {
//4.创建输入流
BufferedInputStream fis = new BufferedInputStream(new FileInputStream(f));
//要访问的资源存在
//如果存在把图片发送给浏览器
os.write("HTTP/1.1 200 OK\r\nContent-Type:image/jpeg\r\n\r\n".getBytes());
//发送数据
int i;
while ((i = fis.read()) != -1) {
os.write(i);
}
//关流
fis.close();
} else {
//要访问的资源不存在
//如果不存在给浏览器"你要访问的资源被外星人劫持了404~"
os.write("HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=UTF-8\r\n\r\n".getBytes());
os.write("你要访问的资源被外星人劫持了404~".getBytes());
}
//关流
os.close();
//关闭
s.close();
}
}catch (Exception e){
//如果你想看报错信息
//e.printStackTrace();
}
}
}
- 上面的代码是单线程代码,当多个浏览器都访问同一个服务器时。服务器需要一个一个处理。
- 接下来我们写一个多线程代码。为每一次访问都开启一个线程
public class Demo服务器多线程 {
public static void main(String[] args) throws Exception{
//创建服务器对象
ServerSocket ss = new ServerSocket(7890);
//可以接受多个浏览器的访问
while(true){
//接受浏览器的请求
Socket s = ss.accept();
//每次接收到浏览器请求就开启新线程
//使用Lambda表达式开启多线程(Runnable是一个函数式接口)
Thread t = new Thread(()->{
try {
//获取输入流
InputStream is = s.getInputStream();
//调用读取一行字符串的方法
//readLine()
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = br.readLine();
//从浏览器发过来的数据
//System.out.println(str); // GET /1.jpg HTTP/1.1
//1.截取用户要访问的资源名称
String[] arr = str.split(" ");
String name = arr[1]; // /1.jpg
//2.查找文件是否存在
File f = new File("day18/发车" + name); //路径: day18/发车/4.jpg
//假设每次执行都需要3秒钟,这样为了看到多线程的效果
Thread.sleep(3000);
//3.获取输出流
BufferedOutputStream os = new BufferedOutputStream(s.getOutputStream());
if (f.exists()) {
//4.创建输入流
BufferedInputStream fis = new BufferedInputStream(new FileInputStream(f));
//要访问的资源存在
//如果存在把图片发送给浏览器
os.write("HTTP/1.1 200 OK\r\nContent-Type:image/jpeg\r\n\r\n".getBytes());
//发送数据
int i;
while ((i = fis.read()) != -1) {
os.write(i);
}
//关流
fis.close();
} else {
//要访问的资源不存在
//如果不存在给浏览器"你要访问的资源被外星人劫持了404~"
os.write("HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=UTF-8\r\n\r\n".getBytes());
os.write("你要访问的资源被外星人劫持了404~".getBytes());
}
//关流
os.close();
//关闭
s.close();
}catch (Exception e){
//异常处理
}
});
t.start();
}
}

浙公网安备 33010602011771号