JAVA网络编程入门
JAVA网络编程入门
软件结构
C/S结构
B/S结构
无论哪一种结构,都离不开网络的支持。网络编程,就是在网络的条件下实现机器间的通信的过程
网络通信协议
网络通信协议:通信双方必须同时遵守才能完成数据交换
UDP:无连接性,数据被限制在64kb,适用于丢包问题不太大的情况,效率高
TCP:面向连接,可靠无差错,三次握手
网络编程三要素:协议,IP地址和端口号
ip地址
查看本机Ip地址:控制台输入ipconfig
查看是否可以和某一台计算机进行网络交换:
ping ip地址
端口号
用协议+IP地址+端口号可以唯一的表示网络中的进程并进行进程间的通信了
软件在启动时可以和操作系统要指定的端口号,或者由操作系统分配随机的端口号
端口号由两个字节组成,范围为0-65535
TCP通信程序
TCP通信可以实现两台计算机之间的数据交互,通信的两端要严格区分客户端和服务器端
客户端和服务器端进行一个数据交流,一共需要4个IO流对象:
? Socket s1=server.accept();//获取客户端的流对象
java.net
套接字(Socket):包含了ip地址和端口号的网络单位(可以借此识别设备和进程)
- 客户端
这里使用Socket的输入流来读,输出流来写,不要混了
- 服务器端
服务器端必须明确知道是哪个客户端请求的服务器,所以要使用accept方法
一个TCP通信的小例子:
TCPServer.java
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.omg.CORBA.portable.InputStream;
/*
*@author JiaDing
*服务器端
*/
public class TCPServer {
public static void main(String[]args)throws IOException{
//创建使用特定端口的对象
ServerSocket server=new ServerSocket(8888);
Socket socket=server.accept();
java.io.InputStream is=socket.getInputStream();
byte[]bytes=new byte[1024];
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));//利用字符数组创建字符串
OutputStream os=socket.getOutputStream();
os.write("收到谢谢".getBytes());//要将字符串转换为字符数组才行
socket.close();//销毁socket对象
server.close();//销毁server对象
; }
}
TCPClient.java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*
*@author JiaDing
*TCP通信的客户端
*使用host(服务器主机的名称/IP地址)和port(端口号)的构造方法
*getOutputStream 返回套接字的输出流,使用其write方法给服务器发送数据
*getInputStream 返回套接字的输入流,使用其read方法读取服务器回写数据
*close关闭套接字
*/
public class TCPClient {
public static void main (String[] args) throws IOException {
Socket socket=new Socket("127.0.0.1",8888);
OutputStream os=socket.getOutputStream();
os.write("你好服务器".getBytes());
InputStream is=socket.getInputStream();
byte[]bytes=new byte[1024];
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));
socket.close();
}
}
TCP通信往往是按字节处理而不是字符处理,因为不是所有类型都是字符
127.0.0.1是什么地址?*
127.0.0.1/8整个都是环回地址,用来测试本机的TCP/IP协议栈,发往这段A类地址数据包不会出网卡,网络设备不会对其做路由。
实例:文件上传
Client.java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/*
*@author JiaDing
*文件上传案例的客户端
*/
public class Client {
public static void main(String[]args)throws IOException {
FileInputStream fis=new FileInputStream("E:\\out.txt");
Socket socket=new Socket("127.0.0.1",8888);
java.io.OutputStream os=socket.getOutputStream();
byte[] re=new byte[1024];//准备了1kb的大小
int len=0;
while((len=fis.read(re))!=-1) {//这里一定要给len=fis.read(re)加一个括号,否则两个等号无法区分优先级
os.write(re,0,len);
}
/*
* 注意!这里有一个很重要的问题!
* 由于我们的判断条件是len!=-1,所以我们无法将文件的结束标记上传过去,这样服务器会一直处于等待状态,造成阻塞
* 而对应的,由于服务器阻塞,所以无法执行回显,is.read()也就无法读入数据,同样陷入阻塞
* 解决办法就是在客户端利用套接字的方法人工结束输出流
*/
socket.shutdownOutput();
InputStream is=socket.getInputStream();
while((len=is.read(re))!=-1) {//这里一定要给len=fis.read(re)加一个括号,否则两个等号无法区分优先级
System.out.println(new String(re,0,len));
}
fis.close();
socket.close();
}
}
Server.java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
*@author JiaDing
*文件上传案例的服务器端
*/
public class Server {
public static void main(String[]args) throws IOException{
ServerSocket ss=new ServerSocket(8888);
Socket socket=ss.accept();
File file=new File("E:\\update");
if(!file.exists())
file.mkdir();
byte[] by=new byte[1024];
InputStream is=socket.getInputStream();
FileOutputStream out=new FileOutputStream("E:\\update\\t1.txt");
int len=0;
while(len!=-1) {
out.write(by, 0, len);
len=is.read(by);
}
OutputStream os=socket.getOutputStream();
os.write("Update is finished!".getBytes());
socket.close();
out.close();
ss.close();
}
}
优化:
- 名称写死了:自定义服务器端命名规则,防止同名文件被覆盖
//自定义文件名规则:域名+毫秒值+随机数
//毫秒值广泛应用在服务器端文件名保存上
String name="jd"+System.currentTimeMillis()+new Random().nextInt(999999)+".txt";
FileOutputStream out=new FileOutputStream("E:\\update\\"+name);
- 服务器上传后就停止:让服务器一直处于监听状态:使用死循环,服务器不关闭
B\S服务器的模拟
服务器代码-返回请求版:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
*@author JiaDing
*BS版本的TCP服务器
*/
public class Server {
public static void main(String[]args)throws IOException{
ServerSocket server=new ServerSocket(8080);
Socket socket=server.accept();
InputStream is=socket.getInputStream();
byte[]by=new byte[1024];
int len=0;
while((len=is.read(by))!=-1) {
System.out.println(new String(by,0,len));
}
}
}
访问时要指明文件夹名\要访问的资源名,如果端口不是80还要在IP后面加上端口号
服务器端结果(其实就是客户端的请求信息):
GET /src/Test1.html HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
服务器应该回写应该网页(文件),我们需要读取文件地址,地址已经包含在了请求第一行
可以使用BufferedReader中的方法readList读取第一行
服务器代码—返回网页版:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
*@author JiaDing
*BS版本的TCP服务器
*/
public class Server {
public static void main(String[]args)throws IOException{
ServerSocket server=new ServerSocket(8080);
Socket socket=server.accept();
InputStream is=socket.getInputStream();
/*byte[]by=new byte[1024];
int len=0;
while((len=is.read(by))!=-1) {
System.out.println(new String(by,0,len));
}*/
//把is网络字节输入流对象转换为字符缓存输入流
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=br.readLine();
String htmlpath=line.split(" ")[1].substring(1);//取第一行中间的地址,去掉最前面的、
//System.out.println(htmlpath);
FileInputStream fis=new FileInputStream(htmlpath);
OutputStream os=socket.getOutputStream();
//写入HTTP协议响应头,固定写法
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
//必须写入空行,否则浏览器不解析
os.write("\r\n".getBytes());
int len=0;
byte[]by=new byte[1024];
while((len=fis.read(by))!=-1) {
os.write(by,0,len);
}
fis.close();
socket.close();
server.close();
}
}
为什么服务器要是多线程呢?
如果不采用多线程,那么服务器只能线型地处理浏览器的请求,浏览器上的资源只能一个一个打开,体验会很差
采样头多线程之后的代码:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
*@author JiaDing
*BS版本的TCP服务器
*/
public class Server {
public static void main(String[]args)throws IOException{
ServerSocket server=new ServerSocket(8080);
while(true) {
Socket socket=server.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream is=socket.getInputStream();
//把is网络字节输入流对象转换为字符缓存输入流
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=br.readLine();
String htmlpath=line.split(" ")[1].substring(1);//取第一行中间的地址,去掉最前面的、
//System.out.println(htmlpath);
FileInputStream fis=new FileInputStream(htmlpath);
OutputStream os=socket.getOutputStream();
//写入HTTP协议响应头,固定写法
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
//必须写入空行,否则浏览器不解析
os.write("\r\n".getBytes());
int len=0;
byte[]by=new byte[1024];
while((len=fis.read(by))!=-1) {
os.write(by,0,len);
}
fis.close();
socket.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
注意这里会报一个错误:java.io.FileNotFoundException: favicon.ico。这是因为浏览器会自动访问网站的图标而我们的网站没有的原因,这个图标必须放在根目录,例如如果访问的地址是“http://127.0.0.1/src/Test1.html”,那么就要放在src文件夹的外面
另外,实验了一下,将服务器的端口改成了80好像并没有什么问题,因为服务器监听的是本机的80端口,而如果我们访问外网的话,应该是访问外网网站服务器的80端口,两者并不冲突。部署在本机上的服务器只能监听到访问本机且本端口的请求。所以,网页中如果有外链,那么打开这个外链的过程和我们的服务器是没有丝毫关系的,我们自建的服务器的好坏不会对其造成影响
JAVA网络编程入门的更多相关文章
- 【Java】Java网络编程菜鸟进阶:TCP和套接字入门
Java网络编程菜鸟进阶:TCP和套接字入门 JDK 提供了对 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protoco ...
- 20145225《Java程序设计》 实验五 Java网络编程及安全
20145225<Java程序设计> 实验五 Java网络编程及安全 实验报告 一.实验内容 基于Java Socket实现安全传输. 基于TCP实现客户端和服务器,结对编程一人负责客户端 ...
- 20145215实验五 Java网络编程及安全
20145215实验五 Java网络编程及安全 实验内容 掌握Socket程序的编写: 掌握密码技术的使用: 设计安全传输系统. 实验步骤 本次实验我的结对编程对象是20145208蔡野,我负责编写客 ...
- JAVA网络编程【转】出处不详
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
- 【转】JAVA 网络编程
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
- 脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?
本文引用了“帅地”发表于公众号苦逼的码农的技术分享. 1.引言 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢 ...
- 脑残式网络编程入门(三):HTTP协议必知必会的一些知识
本文原作者:“竹千代”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.前言 无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交 ...
- 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...
- 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手
.引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道“三次”和“四次”,但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方 ...
随机推荐
- TCP输入 之 tcp_prequeue
在未开启tcp_low_latency的情况下,软中断将skb送上来,加入到prequeue中,然后 在未启用tcp_low_latency且有用户进程在读取数据的情况下,skb入队到prequeue ...
- Qt新安装之后出现Error while building/deploying (kit: Desktop Qt 5.7.0 GCC 64bit) When executing step "Make”
Ubuntu14.04初次安装Qt之后可能出现Error while building/deploying project *** (kit: Desktop Qt 5.7.0 GCC 64bit ...
- 哨兵模式java实例
/** * 测试Redis哨兵模式 * @author liu */ public class TestSentinels { @SuppressWarnings("resource&quo ...
- 时间总线框架之EvenBus
概述 EventBus定义:是一个发布 / 订阅的事件总线. 这么说应该包含4个成分:发布者,订阅者,事件,总线. 那么这四者的关系是什么呢? 很明显:订阅者订阅事件到总线,发送者发布事件. 订阅者可 ...
- [Python]切换工作目录|python将目录切换为脚本所在目录
Python使用os.chdir命令切换python工作目录 代码示例: In []: import os In []: os.system("pwd") /home/wangju ...
- centos6.5 内核 :2.6.32 升级内核
问题: CentOS 6.5 的内核一般都是2.6,在2.6的内核下,Docker运行会比较卡,所以一般会选择升级到更高版本,本次教程升级版本为4.4.102 一.升级内核 1.查看内核版本 u ...
- Java语言 List 和 Array 相互转换
Java语言 List 和 Array 相互转换 List集合 转换为 Array数组 List集合 转换成 Array数组,有 2 种方式,代码如下: import java.util.ArrayL ...
- java解析和组装json以及一些方法的理解
这是一个json格式的字符串 第一种情况(简单格式) String result = "{\"name\":\"小明\",\"age\&qu ...
- 谷歌云服务器XShell登录
一,谷歌云服务器,默认用浏览器进行SSH链接,而且也不告知密码.以Centos为例,先使用浏览器连接 1,给root修改密码 sudo passwd root 2,编辑ssh配置文件 sudo nan ...
- Python--偏函数(Partial)
Python--偏函数(Partial) 出处 https://blog.csdn.net/Appleyk/article/details/77609114 一.什么是偏函数? (1)在Pyth ...