网络编程
1 概念
socket:网络编程
实现网络中 不同电脑之间的数据传输
IP地址(Internet Protocol Address)是指互联网协议地址
IPV4: 4个1个byte的十进制数字 0.0.0.0 -- 255.255.255.255
IPV6: 8个2个byte的16进制数字 0.0.0.0.0.0.0.0 -- ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff
它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
一个字符串用于唯一标识互联网上主机
127.0.0.1 / localhost 表示本地主机
域名: ip地址不宜与记忆 通过一段字符串来和ip地址一一对应
域名服务器:DNS 解析域名与ip的对应关系
PORT:端口 逻辑端口 电脑上安装的所有软件都会分配一个唯一的编号 0-65535 实现互联网数据传输
注意10000以下的端口 不要使用 默认被操作系统的软件使用
2 socket分类
* TCP:Transmission Control Protocol 传输控制协议
可控的 端对端的 字节流传输协议
类似于:打固定电话
* UDP:User Datagram Protocol 用户数据报协议
不可靠的 无需连接的 报文流传输协议
类似于:发电部
3 TCP
tcp的两端:客户端和服务器端
被动接电话的---服务器端
主动打电话的---客户端
主要涉及的类:ServerSocket+Socket
Socket:套接字/传输通道
3.1方法
*ServerSocket:服务器套接字
*构造方法:ServerSocket(int port) 开启服务并制定端口
*普通方法:Socket accept() :等到和获取客户端连接
* void close() :关闭服务
*
*Socket:套接字/传输通道
*构造方法:Socket(String host, int port) 创建连接 并制定服务器端的ip和port
*普通方法:InputStream getInputStream() :获取输入流
* OutputStream getOutputStream() :获取输出流
* void close() :关闭socket
* InetAddress getInetAddress() 获取自己的ip
InetAddress getLocalAddress() 获取对方的ip
int getLocalPort() 获取自己的端口
int getPort() 获取对方的端口
3.1 案例
package com.zhiyou100.day14_socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo01TCP_Server {
/*tcp服务器端
*被动接电话的一端
*1 安装电话 买个号::::创建一个ServerSocket并开启一个端口
*2 等待别人的电话::::等待客户端的连接
*3 接通电话 说和听::::接受和发送信息
*4 挂断电话:::::关闭服务
* */
public static void main(String[] args)throws Exception {
//1 开启服务:创建一个ServerSocket并开启一个端口
ServerSocket server=new ServerSocket(10086);
System.out.println("服务器端开启:::"+10086);
//2 获取客户端的连接
Socket socket=server.accept();//阻塞方法:
//3 获取socket的输入流和输出流 用于接受和发送信息
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//4 接受和发送信息
byte[] arr=new byte[1024];
int n=in.read(arr);
System.out.println("服务器端接收到客户端的信息是:"+new String(arr, 0, n));
System.out.println("服务器端getLocalPort:"+socket.getLocalPort());
System.out.println("服务器端getLocalAddress:"+socket.getLocalAddress().getHostName());
System.out.println("服务器端getInetAddress:"+socket.getInetAddress().getHostName());
System.out.println("服务器端getPort:"+socket.getPort());
out.write("好的!收到!再见".getBytes());
//5 关闭服务
server.close();
}
}
package com.zhiyou100.day14_socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo01TCP_Client {
/*TCP:客户端
* 客户端:主动打电话
* 1 准备电话 准备电话线 拨通对方的号码----创建socket 指定服务器端的ip和port
* 2 电话接通 说和听----获取输入流和输出流 进行数据传输
* 3 挂断电话 撤销电话线----关闭socket
* */
public static void main(String[] args)throws Exception {
//1 创建socket 指定服务器端的ip和port
Socket socket=new Socket("192.168.118.107", 10086);
System.out.println("客户端创建连接成功!——————————");
//2 获取输入流和输出流
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//3 发送和接受数据
out.write("你好,服务器端:给我带个包子!".getBytes());
byte[] arr=new byte[1024];
int n=in.read(arr);
System.out.println("客户端接收到服务器端的信息是:"+new String(arr,0,n));
System.out.println("客户端getLocalPort:"+socket.getLocalPort());
System.out.println("客户端getLocalAddress:"+socket.getLocalAddress().getHostName());
System.out.println("客户端getInetAddress:"+socket.getInetAddress().getHostName());
System.out.println("客户端getPort:"+socket.getPort());
//4 关闭sokcet
socket.close();
}
}
3.2 实现互发信息
package com.zhiyou100.day14_socket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class Demo02TCP_Client {
//客户端从键盘读取信息 把读取的信息发给服务器端 然后再接受 直到发送了886
public static void main(String[] args) throws Exception{
//1 创建socket 制定服务器的ip和端口
Socket socket=new Socket("localhost", 10086);
//2 获取输入流和输出流
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//3 获取系统输入流
BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
while(true){
String line=bin.readLine();//从键盘读取一行信息
out.write(line.getBytes());//把读取的信息通过socket发送给客户端
if(line.equals("886")){
break;
}
byte[] arr=new byte[1024];
int n=in.read(arr);
String message=new String(arr, 0,n);
System.out.println("接收到10086的信息是:"+message);
}
//4 关闭流和socket
//系统相关的流不能关闭
socket.close();
}
}
package com.zhiyou100.day14_socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo02TCP_Server {
//: 服务器端接受信息:把信息转换后发送给客户端
public static void main(String[] args) throws Exception{
//1 开启服务
ServerSocket ss=new ServerSocket(10086);
//2 获取连接
Socket socket=ss.accept();
//3 获取视如流和输出流
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//4 接受和发送数据
while(true){
byte[] arr=new byte[1024];
int n=in.read(arr);
String message=new String(arr,0,n);
if(message.equals("886")){//如果接受到886就结束
break;
}
message=change(message);
out.write(message.getBytes());
}
//5 关闭服务
ss.close();
}
public static String change(String s){
String ss="";
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(Character.isUpperCase(c)){
ss+=Character.toLowerCase(c);
}else if(Character.isLowerCase(c)){
ss+=Character.toUpperCase(c);
}else if(!Character.isDigit(c)){
ss+=c;
}
}
return ss;
}
}
3.3 实现文件上传
package com.zhiyou100.day14_socket;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Demo03TCP_Client {
//客户端:先发送源文件的名字 再发送源文件的内容
public static void main(String[] args) throws Exception{
//1 创建socket
Socket socket=new Socket("localhost",10086);
//2 获取流
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
File yuan=new File("C:\\Users\\Administrator\\Desktop\\imgs\\2.jpg");
BufferedInputStream bin=new BufferedInputStream(new FileInputStream(yuan));
out.write(yuan.getName().getBytes());//发送文件的名字
byte[] arr=new byte[1024];
int n;
while((n=bin.read(arr))!=-1){
out.write(arr, 0, n);
}
//关闭socket的输出流
socket.shutdownOutput();
//4 关闭流和socket
socket.close();
bin.close();
}
//xml swing socket io thread
}
package com.zhiyou100.day14_socket;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo03TCP_Server {
//文件上传:先传递文件名 再传递文件内容
public static void main(String[] args)throws Exception {
//1 开启服务
ServerSocket ss=new ServerSocket(10086);
//2 获取连接
Socket socket=ss.accept();
//3 获取流
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//4 先获取文件名字:
byte[] arr=new byte[1024];//默认第一次发送的信息就是文件名字
int n=in.read(arr);
String fileName=new String(arr,0,n);
//创建输出流与目的文件关联
BufferedOutputStream bout=
new BufferedOutputStream(new FileOutputStream("src/com/zhiyou100/day14_socket/"+fileName));
//一边从socket中读信息 一边把读取的信息写到目的文件中
while(true){
n=in.read(arr);
if(n==-1){
break;
}
bout.write(arr, 0, n);
}
//关闭流和服务
bout.close();
ss.close();
}
}
4 UDP
4.1 方法
* udp:报文流传输协议
* 主要类:DatagramPacket+DatagramSocket
* DatagramPacket:对发送和接受的信息的封装
* 构造方法:(创建报文对象:带地址用于发送 不带地址用与接受)
* DatagramPacket(byte[] buf, int offset, int length):用于接受的报文
DatagramPacket(byte[] buf, int offset, int length, InetAddress ip, int port) 用于发送的报文
普通方法:
InetAddress getAddress() :获取对方的ip
int getPort() :获取对方的port
byte[] getData()
int getLength()
DatagramSocket:报文流的套接字
构造方法:
DatagramSocket(int port) :指定开启的打开
普通方法:
void receive(DatagramPacket p) :接受报文对象
void send(DatagramPacket p) :发送报文
void close() :关闭套接字
InetAddress getLocalAddress() :获取本地的ip
int getLocalPort() :获取本地的port
4.2 案例
//接收方
//1 创建socket
DatagramSocket scoket=new DatagramSocket(10010);
//2 创建一个空的datagramepacket用于接受信息
DatagramPacket packet=new DatagramPacket(new byte[1024], 1024);
//3接受信息
scoket.receive(packet);
System.out.println("10010:packet.getPort="+packet.getPort());
System.out.println("10010:packet.getAddress="+packet.getAddress());
//System.out.println("10010:scoket.getPort()="+scoket.getPort());
//System.out.println("10010:scoket.getInetAddress()="+scoket.getInetAddress().getHostName());
System.out.println("10010:scoket.getLocalPort()="+scoket.getLocalPort());
System.out.println("10010:scoket.getLocalAddress()="+scoket.getLocalAddress().getHostName());
//4 解析信息
String message=new String(packet.getData(),0,packet.getLength());
System.out.println("10010接收到的信息是:"+message);
//5 关闭socket
scoket.close();
//1 创建datagramsocket
DatagramSocket socket=new DatagramSocket(10086);
//2 创建一个datagrampacket
String message="udp你好!";
byte[] arr=message.getBytes();
DatagramPacket packet=new DatagramPacket(arr, arr.length, InetAddress.getByName("127.0.0.1"), 10010);
//3 发送信息
socket.send(packet);
System.out.println("10086:packet.getPort="+packet.getPort());
System.out.println("10086:packet.getAddress="+packet.getAddress());
//System.out.println("10086:scoket.getPort()="+socket.getPort());
//System.out.println("10086:scoket.getInetAddress()="+socket.getInetAddress().getHostName());
System.out.println("10086:scoket.getLocalPort()="+socket.getLocalPort());
System.out.println("10086:scoket.getLocalAddress()="+socket.getLocalAddress().getHostName());
//4 关闭socket
socket.close();
4.3 实现互发信息
package com.zhiyou100.day14_socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Demo05UDP_1 {
//键盘读取信息 把信息发送给对方 接受对方的信息:对方把信息转换
public static void main(String[] args) throws Exception{
//1 创建socket
DatagramSocket socket=new DatagramSocket(10086);
//2 获取系统输入流
BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
//逐行读取键盘的信息
while(true){
String line=bin.readLine();
byte[] arr=line.getBytes();
//创建datagrampacket封装发送的信息
DatagramPacket sendPacket=
new DatagramPacket(arr, arr.length, InetAddress.getByName("localhost"), 10010);
//发送信息
socket.send(sendPacket);
if(line.equals("886")){
break;
}
//创建一个空的datagrampacket接受信息
DatagramPacket receivePacket=new DatagramPacket(new byte[1024], 1024);
//接受信息
socket.receive(receivePacket);
//解析数据
String message=new String(receivePacket.getData(),0,receivePacket.getLength());
System.out.println(socket.getLocalPort()+"接收到"+receivePacket.getPort()+"的信息是:"+message);
}
//关闭socket
socket.close();
}
}
package com.zhiyou100.day14_socket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Demo05UDP_2 {
public static void main(String[] args) throws Exception{
//1 创建socket
DatagramSocket socket=new DatagramSocket(10010);
//2 循环的接受和发送
while(true){
//定义一个空的报文对象 接受信息
DatagramPacket receivePacket=new DatagramPacket(new byte[1024], 1024);
socket.receive(receivePacket);
//解析信息
String message=new String(receivePacket.getData(),0,receivePacket.getLength());
System.out.println(socket.getLocalPort()+"接收到"+receivePacket.getPort()+"的信息是:"+message);
if(message.equals("886")){
break;
}
//对字符串进行循环
message=change(message);
byte[] arr=message.getBytes();
DatagramPacket sendPacket=
new DatagramPacket(arr, arr.length,receivePacket.getAddress(),receivePacket.getPort());
socket.send(sendPacket);
}
//3关闭socket
socket.close();
}
public static String change(String s){
String ss="";
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(Character.isUpperCase(c)){
ss+=Character.toLowerCase(c);
}else if(Character.isLowerCase(c)){
ss+=Character.toUpperCase(c);
}else if(!Character.isDigit(c)){
ss+=c;
}
}
return ss;
}
}
4.4 实现文件上传
package com.test.test4;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//发送
public class UDP_Upload_01 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(10086);
String srcFile = "ServerFile\\Day01\\day01\\ListFilesTest.java";
byte[] buff = srcFile.getBytes();
DatagramPacket sendPacket = new DatagramPacket(buff, buff.length, InetAddress.getByName("localhost"), 10010);
socket.send(sendPacket);
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
socket.receive(receivePacket);
String message = new String(receivePacket.getData(),0,receivePacket.getLength());
System.out.println(message);
socket.close();
}
}
package com.test.test4;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//发送
public class UDP_Upload_01 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(10086);
String srcFile = "ServerFile\\Day01\\day01\\ListFilesTest.java";
byte[] buff = srcFile.getBytes();
DatagramPacket sendPacket = new DatagramPacket(buff, buff.length, InetAddress.getByName("localhost"), 10010);
socket.send(sendPacket);
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
socket.receive(receivePacket);
String message = new String(receivePacket.getData(),0,receivePacket.getLength());
System.out.println(message);
socket.close();
}
}
5 模拟QQ群聊
package com.zhiyou100.day14_socket;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class Demo06ChatClient {
public static void main(String[] args)throws Exception {
//注意1:所有的客户端只需要给服务器连接即可
//注意2: 对于客户端的socket的输入和输出需要使用多线程
Socket socket=new Socket("localhost", 10086);
System.out.println(socket.getLocalAddress().getHostName()+"_"+socket.getLocalPort()+"加入聊天了!!!");
new ClientInThread(socket).start();
new ClientOutThread(socket).start();
}
}
class ClientOutThread extends Thread{
Socket socket;
public ClientOutThread(Socket socket) {
this.socket = socket;
}
public void run(){
try{
BufferedWriter bout=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
while(true){
String line=bin.readLine();
bout.write(line);
bout.flush();
if(line.endsWith("886")){
socket.shutdownOutput();
}
}
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
class ClientInThread extends Thread{
Socket socket;
public ClientInThread(Socket socket) {
this.socket = socket;
}
public void run(){
try{
InputStream in=socket.getInputStream();
while(true){
byte[] arr=new byte[1024];
int n=in.read(arr);
System.out.println(socket.getLocalAddress().getHostName()+"_"+
socket.getLocalPort()+
"接收到信息:"+new String(arr,0,n));
}
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
package com.zhiyou100.day14_socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Demo06ChatServer {
public static ArrayList<Socket> socketList=new ArrayList<>();
public static void main(String[] args)throws Exception {
//群聊:服务器端:1 需要时刻等待连接 2 接收到的所有信息 必须给所有连接再发送一边
ServerSocket ss=new ServerSocket(10086);
while(true){
Socket socket=ss.accept();
socketList.add(socket);
new ChatThread(socket).start();
//System.out.println("main::"+socketList.size());
}
}
}
//2 创建一个线程:实现服务器端接受制定socket的信息 把信息发送给所有的socket
class ChatThread extends Thread{
Socket socket;
public ChatThread(Socket socket) {
this.socket = socket;
}
public void run(){
try{
//获取当前socket的输入流
InputStream in=socket.getInputStream();
while(true){
byte[] arr=new byte[1024];
int n=in.read(arr);
String message=new String(arr,0,n);
message=socket.getInetAddress().getHostName()+"_"+socket.getPort()+"说:"+message;
//System.out.println(socket.getPort()+"::"+Demo06ChatServer.socketList.size());
//把arr中读取的信息写道所有的socket的输出流中
for (int i = 0; i <Demo06ChatServer.socketList.size(); i++) {
OutputStream out=Demo06ChatServer.socketList.get(i).getOutputStream();
out.write(message.getBytes());
}
}
}catch(Exception e){throw new RuntimeException(e);}
}
}
6 内部类
A类定义在B类中 ,A类就是B类的内部类
如果A类的存在依赖B类的存在而存在时 可以把A类定义为B类的内部类
内部类1:成员内部类
内部类是外部类的实例成员
package com.zhiyou100.day14_socket;
public class Demo07Inner {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer07.Inner07 i1;//定义引用
i1=new Outer07().new Inner07();//创建内部类对象 需要通过外部类对象来创建
Outer07 o1=new Outer07();
i1=o1.new Inner07();
i1.test();
}
}
class Outer07{
String name="外部类name";
class Inner07{
String name="内部类name";
public void test(){
String name="局部变量name";
System.out.println("name="+name);
System.out.println("this.name="+this.name);
System.out.println("Outer07.this.name="+Outer07.this.name);
}
}
}
内部类2:静态内部类
内部类是外部类的静态成员
package com.zhiyou100.day14_socket;
public class Demo08Inner {
public static void main(String[] args) {
Outer08.Inner08 i1;//定义引用
i1=new Outer08.Inner08();//创建对象
}
}
class Outer08{
int a=1;
static int b=2;
static class Inner08{
int c=1;
void hehe(){
System.out.println("c="+c);
//System.out.println("a="+a); 静态内部类不能访问外部类的实例成员
System.out.println("b="+b);
}
}
}
内部类3:局部内部类
内部类定义在代码块或者方法中
package com.zhiyou100.day14_socket;
public class Demo09Inner {
//局部内部类:定义在方法或者代码块中
public static void main(String[] args) {
}
}
class Outer09{
{
class Inner091{}
Inner091 i1=new Inner091();//局部内部类 只能再当前大括号内使用
}
void show(){
class Inner091{
}
Inner091 i1=new Inner091();//局部内部类 只能再当前大括号内使用
}
}
内部类4:匿名内部类
没有名字的局部内部类
package com.zhiyou100.day14_socket;
import java.util.concurrent.FutureTask;
public class Demo10Inner {
public static void main(String[] args) {
//想使用Fu的hehe方法
//方式1:定义子类 创建子类对象 通过子类对象调用方法即可
new Zi1().hehe();
//方式2:
//:如果此子类的对象只创建一个 可以使用匿名内部类实现 方法的调用
Fu fu=new Fu() {
void show() {}
};
fu=new Fu() {
void show() {}
};
fu=new Fu() {
void show() {}
};
}
}
class Zi1 extends Fu{
void show() {}
}
abstract class Fu{
void hehe(){}
abstract void show();
}