------- android培训、java培训、期待与您交流! ----------
不要试图给自己找任何借口,错误面前没人爱听那些借口.
屡败屡战,然后,恭喜你,你成功了.
每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址。
ipconfig:查看本机IP
ping:测试连接
本地回路地址:127.0.0.1
IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。已经用尽。
IPv6:8组,每组4个16进制数。
1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
1a2b::aaaa:0000:0000:0000:aabb:1f2f
1a2b:0000:aaaa::aabb:1f2f
1a2b:0000:aaaa::0000:aabb:1f2f
1a2b:0000:aaaa:0000::aabb:1f2f
每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
端口号范围从0-65535
编写网络应用就需要绑定一个端口号,尽量使用10000以上的,1024以下的基本上都被系统程序占用了。
常用端口
mysql: 3306
oracle: 1521
web: 80
tomcat: 8080
QQ: 4000
feiQ: 2425
为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
UDP
面向无连接,数据不安全,速度快。不区分客户端与服务端。
TCP
面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
Socket:套接字,通信的端点
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。
创建DatagramSocket
创建DatagramPacket
使用DatagramSocket发送DatagramPacket
关闭DatagramSocket
代码:
import java.net.*;
class UdpSend{
public static void main(String[]args)throws Exception {
// 1,建立udp的socket服务。
DatagramSocket ds = newDatagramSocket(8888);//指定发送端口,不指定系统会随机分配。
// 2,明确要发送的具体数据。
String text = "udp传输演示哥们来了";
byte[] buf = text.getBytes();
// 3,将数据封装成了数据包。
DatagramPacket dp = new DatagramPacket(buf,
buf.length,InetAddress.getByName("10.1.31.127"),10000);
// 4,用socket服务的send方法将数据包发送出去。
ds.send(dp);
// 5,关闭资源。
ds.close();
}
}
创建DatagramSocket
创建DatagramPacket
使用DatagramSocket接收DatagramPacket
关闭DatagramSocke
代码:
class UdpRece {
public static void main(String[] args)throws Exception{
// 1,创建udp的socket服务。
DatagramSocket ds = newDatagramSocket(10000);
// 2,定义数据包,用于存储接收到数据。先定义字节数组,数据包会把数据存储到字节数组中。
byte[] buf = new byte[1024];
DatagramPacket dp = newDatagramPacket(buf,buf.length);
// 3,通过socket服务的接收方法将收到的数据存储到数据包中。
ds.receive(dp);//该方法是阻塞式方法。
// 4,通过数据包的方法获取数据包中的具体数据内容,比如ip,端口,数据等等。
String ip =dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = newString(dp.getData(),0,dp.getLength());//将字节数组中的有效部分转成字符串。
System.out.println(ip+":"+port+"--"+text);
// 5,关闭资源。
ds.close();
}
}
两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,称之为socket流。该流中既有读取,也有写入。
tcp的两个端点:一个是客户端,一个是服务端。
客户端:对应的对象,Socket
服务端:对应的对象,ServerSocket
创建Socket连接服务端
调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的管道流
输入流可以读取服务端输出流写出的数据
输出流可以写出数据到服务端的输入流
客户端
import java.net.*;
import java.io.*;
//需求:客户端给服务器端发送一个数据。
class TcpClient{
public static void main(String[] args) throwsException{
Socket s = newSocket("10.1.31.69",10002);
OutputStream out = s.getOutputStream();//获取了socket流中的输出流对象。
out.write("tcp演示,哥们又来了!".getBytes());
s.close();
}
}
创建ServerSocket
调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的管道流
输入流可以读取客户端输出流写出的数据
输出流可以写出数据到客户端的输入流
class TcpServer{
public static void main(String[] args)throws Exception{
ServerSocket ss = newServerSocket(10002);//建立服务端的socket服务
Socket s = ss.accept();//获取客户端对象
String ip =s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
// 可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。
InputStream in = s.getInputStream();//读取客户端的数据,使用客户端对象的socket读取流
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
// 如果通讯结束,关闭资源。注意:要先关客户端,在关服务端。
s.close();
ss.close();
}
}
package com.itheima.udp.exercise;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.Point;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
public class GUI_Chat extends Frame {
privatestatic final long serialVersionUID = 1L;
privateTextArea viewTextArea = new TextArea(); //用来显示聊天记录的文本域
privateTextArea sendTextArea = new TextArea(5, 1); //用来输入消息的文本域(指定行数和列数, 列数由于是边界布局所以无效)
privateTextField textField = new TextField(20); //用来输入IP的文本框
privateButton sendButton = new Button("发送");
privateButton clearButton = new Button("清屏");
privateButton logButton = new Button("记录");
privateButton shakeButton = new Button("震动");
privatePanel southPanel = new Panel(); //放在南边的面板(TextField, 4个Button)
privatePanel cenerPanel = new Panel(); //放在中间的面板(2个TextArea)
privateDatagramSocket socket;
privateBufferedWriter bw;
/*
* 构造函数
*/
publicGUI_Chat() {
init(); //初始化
generateSouthPanel(); // 构造南边的面板
generateCenterPanel(); // 构造中间的面板
addListener(); // 添加监听器
setVisible(true); // 显示
newReceiveThread().start(); // 开启接收数据的线程
}
/*
* 初始化
* 设置Frame的标题, 大小, 位置
* 创建了Socket对象
*/
privatevoid init() {
setTitle("GUI聊天室");
setSize(400,600);
setLocation(800,50);
setMinimumSize(newDimension(400, 300));
try{
socket= new DatagramSocket(); // 发送端Socket可以不用指定地址(本机)和端口(随机的)
bw= new BufferedWriter(new FileWriter("log.txt", true));
}catch (Exception e) {
e.printStackTrace();
}
}
/*
* 构造南边的面板
* 把TextField和4个Button一起放入Panel
* 把Panel放在南边
*/
privatevoid generateSouthPanel() {
southPanel.add(textField);
southPanel.add(sendButton);
southPanel.add(clearButton);
southPanel.add(logButton);
southPanel.add(shakeButton);
add(southPanel,BorderLayout.SOUTH); // 把面板放在Frame的南边
}
/*
* 构造中间的面板
* 把两个TextArea装入Panel
* 把Panel放在中间
*/
privatevoid generateCenterPanel() {
cenerPanel.setLayout(newBorderLayout()); // 把面板改为边界布局
cenerPanel.add(viewTextArea,BorderLayout.CENTER); // 用来显示的文本域放在中间
cenerPanel.add(sendTextArea,BorderLayout.SOUTH); // 用来发送的文本域放在下面
add(cenerPanel,BorderLayout.CENTER); //把整个面板放在Frame的中间
viewTextArea.setEditable(false); // 设置为不可编辑, 会改变背景色为灰色
viewTextArea.setBackground(Color.WHITE); // 设置背景色为白色
}
/*
* 给各个组件添加添加监听器
*/
privatevoid addListener() {
addWindowListener(newWindowAdapter() { //关闭窗体时, 释放资源, 退出程序
publicvoid windowClosing(WindowEvent e) {
try{
bw.close();
socket.close();
System.exit(0);
}catch (IOException ex) {
ex.printStackTrace();
}
}
});
sendButton.addActionListener(newActionListener() { // 点击发送按钮时
publicvoid actionPerformed(ActionEvent e) {
send();
}
});
clearButton.addActionListener(newActionListener() {
publicvoid actionPerformed(ActionEvent e) {
viewTextArea.setText("");
}
});
logButton.addActionListener(newActionListener() {
publicvoid actionPerformed(ActionEvent e) {
showLog();
}
});
sendTextArea.addKeyListener(newKeyAdapter() {
publicvoid keyPressed(KeyEvent e) {
if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER ||e.isAltDown() && e.getKeyCode() == KeyEvent.VK_S) {
send();
e.consume(); // 取消这个事件
}
}
});
shakeButton.addActionListener(newActionListener() {
publicvoid actionPerformed(ActionEvent e) {
sendShake();
}
});
}
privatevoid sendShake() {
try{
Stringip = textField.getText().trim();
DatagramPacketpacket = new DatagramPacket(new byte[] { -1 }, 1, InetAddress.getByName(ip), 20000);
socket.send(packet);
}catch (Exception e) {
e.printStackTrace();
}
}
/*
* 发送消息
*/
privatevoid send() {
Stringmsg = sendTextArea.getText(); //获取要发送的内容
Stringip = textField.getText().trim(); //获取目标地址
ip= ip.length() == 0 ? "255.255.255.255" : ip; // 如果没填IP, 默认改为群发地址
try{
DatagramPacketpacket = new DatagramPacket(msg.getBytes(), msg.getBytes().length,InetAddress.getByName(ip), 20000); // 创建Packet
Stringtime = getTimeString();
Stringinfo = time + " 我对 " +(ip.equals("255.255.255.255") ? "所有人" : ip) + " 说:\r\n" +msg + "\r\n\r\n";
synchronized(this) {
socket.send(packet); // 发送
viewTextArea.append(info); // 显示发送的内容到TextView
bw.write(info); //保存聊天记录
}
sendTextArea.setText(""); // 清空文本域
sendTextArea.requestFocus(); // 控制文本域重新获得焦点
}catch (Exception e) {
e.printStackTrace();
}
}
/*
* 获取当前时间字符串
*/
privateString getTimeString() {
Datedate = new Date();
SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
returnsdf.format(date);
}
/*
* 用来接收数据的线程
* 不停地循环接收数据
* 收到数据后显示到TextArea中
*/
privateclass ReceiveThread extends Thread {
publicvoid run() {
try{
DatagramSocketsocket = new DatagramSocket(20000);
DatagramPacketpacket = new DatagramPacket(new byte[1024 * 1024], 1024 * 1024);
while(true) {
socket.receive(packet); //收取数据
byte[]arr = packet.getData(); //获取packet中的数据
intlen = packet.getLength(); //获取长度
if(len == 1 && arr[0] == -1) {
shake();
continue;
}
Stringmsg = new String(arr, 0, len); //把字节数据转为String
Stringip = packet.getAddress().getHostAddress(); //从packet中获取发送端的获取IP
Stringtime = getTimeString(); //获取当前时间
Stringinfo = time + " " + ip + " 对我说:\r\n" + msg + "\r\n\r\n";
synchronized(GUI_Chat.this) { //用外部类对象当作锁对象
viewTextArea.append(info); // 显示到TextView
bw.write(info); //保存聊天记录
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* 从文件中读取聊天记录
* 显示到TextArea中
*/
privatevoid showLog() {
try{
bw.flush(); // 把缓冲区中数据刷出
FileInputStreamfis = new FileInputStream("log.txt");
ByteArrayOutputStreambaos = new ByteArrayOutputStream();
byte[]buffer = new byte[1024];
intlen;
while((len = fis.read(buffer)) != -1) //从文件读取到内存
baos.write(buffer,0, len);
fis.close();
baos.close();
Stringlog = new String(baos.toByteArray()); // 从内存获取数据转为字符串
viewTextArea.setText(log); //显示
}catch (Exception e) {
e.printStackTrace();
}
}
privatevoid shake() {
try{
Pointp = getLocation();
setLocation(p.x- 20, p.y - 20);
Thread.sleep(20);
setLocation(p.x+ 20, p.y + 20);
Thread.sleep(20);
setLocation(p.x+ 20, p.y - 20);
Thread.sleep(20);
setLocation(p.x- 20, p.y + 20);
Thread.sleep(20);
setLocation(p);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
publicstatic void main(String[] args) {
newGUI_Chat();
}
}
客户端:
package com.itheima.tcp.exercise;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
importjava.io.PrintStream;
importjava.net.Socket;
importjava.util.Scanner;
public classExercise2_UploadClient {
public static void main(String[] args)throws Exception {
// 2.创建Socket, 指定服务端地址和端口, 发起请求
Socket socket = newSocket("192.168.1.100", 40000);
// 4.获取输入输出流
InputStream is =socket.getInputStream();
OutputStream os =socket.getOutputStream();
BufferedReaderbr = new BufferedReader(new InputStreamReader(is));
PrintStream ps = newPrintStream(os);
// 5.从键盘输入读取一个文件路径, 验证是否存在, 是否是文件夹
File file = getFile();
// 6.把文件名和文件大小发送到服务端
ps.println(file.getName());
ps.println(file.length());
// 8.接收结果, 如果已存在给予提示, 程序退出
String result =br.readLine();
if ("存在".equals(result)) {
System.out.println("文件已存在, 请不要重复上传!");
return;
}
// 9.定义输入流指向文件, 读取文件写出到网络
FileInputStream fis = newFileInputStream(file);
long filelength =Long.parseLong(result); // 服务端已完成的大小
fis.skip(filelength); //上次完成了多少就跳过多少
byte[] buffer = newbyte[1024];
int len;
while ((len =fis.read(buffer)) != -1) // 读取文件
os.write(buffer, 0,len); // 写到网络
fis.close();
socket.close();
System.out.println("上传完毕!");
}
private static File getFile() {
System.out.println("请输入要上传的文件路径:");
Scanner scanner = newScanner(System.in);
while (true) {
File file = newFile(scanner.nextLine());
if (!file.exists())
System.out.println("您输入的路径不存在, 请重新输入:");
else if(file.isDirectory())
System.out.println("暂不支持文件夹上传, 请输入一个文件路径:");
else
returnfile;
}
}
}
-------------------------------------------------------------------------------==
服务端:
packagecom.itheima.tcp.exercise;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
importjava.io.PrintStream;
importjava.net.ServerSocket;
importjava.net.Socket;
public classExercise2_UploadServer {
public static void main(String[] args)throws Exception {
// 1.创建ServerSocket, 定义循环, 循环中接收客户端请求, 开启新线程
ServerSocket serverSocket =new ServerSocket(40000);
while (true) {
final Socket socket= serverSocket.accept();
new Thread(){
public voidrun() {
try{
//3.获取输入输出流
InputStreamis = socket.getInputStream();
OutputStreamos = socket.getOutputStream();
BufferedReaderbr = new BufferedReader(new InputStreamReader(is));
PrintStreamps = new PrintStream(os);
//7.接收文件名和文件大小, 查找文件是否存在, 是否已完成上传
Stringfilename = br.readLine();
longfilelength = Long.parseLong(br.readLine());
Filefile = new File("F:/Upload", filename);
if(file.exists() && file.length() == filelength) {
ps.println("存在");
return;
}else {
ps.println(file.length()); // 写回文件大小(0或已完成的大小)
}
Stringip = socket.getInetAddress().getHostAddress();
System.out.println(ip+ (file.exists() ? " 断点续传: " :" 开始上传: ") +filename);
longstart = System.currentTimeMillis();
//10.定义输出流指向文件, 从网络中读取数据写出到文件
FileOutputStreamfos = new FileOutputStream(file, true);
byte[]buffer = new byte[1024];
intlen;
while((len = is.read(buffer)) != -1) //读取网络
fos.write(buffer,0, len); // 写出文件
fos.close();
socket.close();
longstop = System.currentTimeMillis();
System.out.println(ip+ " 上传完毕: " + filename+ ", 耗时: " + (stop -start) + "毫秒.");
}catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
------- android培训、java培训、期待与您交流! ----------