网络编程
网络编程也叫socket编程,套接字编程,网络编程。
Socket套接字:网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
Socket原理机制:
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。
网络编程三要素
网络编程三要素:
ip:
一个计算的标示(找到这个计算机)
端口:
应用程序都会对应一个端口,用来进行通信,有效端口:0~65535,其中0~1024系统使用或保留端口(360查看端口)。
协议:
总共有2种协议(TCP,UDP)
1. 特殊的IP地址:
127.0.0.1 本地回环地址,用来做一些本地测试;
ping IP地址: 用来检测本机是否可以和指定的IP地址的计算机可以进行正常通讯;
ipconfig用来查看IP地址;
xxx.xxx.xxx.255 广播地址。
2. 端口号
物理端口:物理设备对应的端口,网卡口
逻辑端口:用来标示我们的计算机上的进程,端口号的有效范围应该是 0-65535,其中0-1024被系统占用或者保留
3. 协议
UDP
把数据打成一个数据包 , 不需要建立连接
数据包的大小有限制不能超过64k
因为无连接,所以属于不可靠协议(可能丢失数据)
因为无连接 ,所以效率高
TCP
需要建立连接,形成连接通道
数据可以使用连接通道直接进行传输,无大小限制
因为有链接,所以属于可靠协议
因为有链接,所以效率低
InetAddress:IP地址的描述类
为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress 供我们使用此类表示互联网协议 (IP) 地址。
package com.wy.inet;
import java.net.InetAddress;
public class InetTest {
public static void main(String[] args) throws Exception {
//ip地址可以设置为自己的ip地址测试一下
InetAddress address = InetAddress.getByName("192.168.20.11");
//获取主机地址
String ha = address.getHostAddress();
//获取主机名
String name = address.getHostName();
System.out.println(ha);
System.out.println(name);
}
}
UDP编程
UDP协议的特点:
1.把数据打包
2.不需要建立连接,也称为面向无连接协议
3.数据需打包,数据大小有限制64k
4.无需建立连接,所以不可靠
5.速度快
UDP通信的步骤:
发送端步骤,UDP发送数据的步骤:
A:创建UDP发送数据端Socket对象
B:创建数据包,并给出数据,把数据打包
C:通过Socket对象发送数据包
D:释放资源
接收端步骤:
UDP协议接收数据步骤:
A:创建UDP接收数据端Socket对象
B:创建一个接收数据的数据包
C:接收数据,数据在数据包中
D:解析数据包,并把数据显示在控制台
E:释放资源
发送段代码:
package com.wy.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpClient {
public static void main(String[] args) throws Exception {
//建立发送Socket
DatagramSocket ds = new DatagramSocket();
byte[] buf = "I love xcc".getBytes();
int len = buf.length;
InetAddress address = InetAddress.getByName("192.168.20.11");
int port = 9999;
//发送数据包的参数为发送数据,发送数据长度,发送地址(InetAddress类型),端口号
DatagramPacket dp = new DatagramPacket(buf, len, address, port);
ds.send(dp);
ds.close();
}
}
服务端代码:
package com.wy.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpServer {
public static void main(String[] args) throws Exception {
//接收端Socket
DatagramSocket ds = new DatagramSocket(9999);
//使用一个字节数组接收
byte[] buf = new byte[1024];
int length = buf.length;
//创建接收端数据包,用于存放接收到的数据
DatagramPacket dp = new DatagramPacket(buf, length);
//进行接收
ds.receive(dp);
//将接受到的数据打印到控制台
System.out.println(new String(buf,0,length));
}
}
运行的时候,先运行客户端,再运行服务端;
使用UDP协议实现一个聊天功能:
客户端代码如下:
package com.wy.udpmultthread;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Scanner;
public class UdpClient implements Runnable{
DatagramSocket ds;
public UdpClient(DatagramSocket ds){
this.ds = ds;
}
@Override
public void run() {
//键盘录入数据
Scanner sc = new Scanner(System.in);
try {
InetAddress address = InetAddress.getByName("192.168.20.11");
//指定一个端口,只要大于1024,小于65535,即可
int port = 20000;
String line;
while((line = sc.nextLine())!= null){
int len = line.getBytes().length;
//建立发送端数据包
DatagramPacket dp = new DatagramPacket(line.getBytes(),len,address,port);
//发送数据
ds.send(dp);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
服务端代码如下:
package com.wy.udpmultthread;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpServer implements Runnable{
DatagramSocket ds;
//使用构造函数,是为了使两个线程使用同一个DatagramSocket
public UdpServer(DatagramSocket ds){
this.ds = ds;
}
@Override
public void run() {
try {
byte[] buf = new byte[1024];
int len = buf.length;
DatagramPacket dp = new DatagramPacket(buf, len);
ds.receive(dp);
System.out.println(new String(buf,0,len));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试:
package com.wy.udpmultthread;
import java.net.DatagramSocket;
public class MultiTreadTest {
public static void main(String[] args) throws Exception {
DatagramSocket sk = new DatagramSocket();
new Thread(new UdpClient(sk)).start();
new Thread(new UdpServer(sk)).start();
}
}
如果将ip改为192.168.20.255,则是广播地址,可以实现群聊。
TCP编程
TCP特点:
1.需要建立通道
2.传送大量数据无限制
3.面向连接
4.可靠
5.速度慢
TCP协议通信步骤:
发送端:
TCP协议发送数据步骤:
A:创建TCP协议发送端Socket对象,指定服务器IP及端口
B:获取输出流,并写数据
C:释放资源
TCP协议是不能直接运行客户端的,必须先运行服务器。因为他是一种可靠的协议。
接收端:
TCP协议接收数据步骤:
A:创建TCP协议接收端Socket对象
B:监听客户端连接
C:获取输入流,并读取数据,显示在控制台
D:释放资源
客户端给服务端发送数据
客户端:
package com.wy.tcp;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) throws Exception {
//发送端Socket
Socket sk = new Socket("192.168.20.11", 10000);
//键盘录入数据
Scanner sc = new Scanner(System.in);
String line ;
while(true){
line= sc.nextLine();
//将数据写入到Socket的输出流中
OutputStream os = sk.getOutputStream();
os.write(line.getBytes());
}
}
}
服务端代码:
package com.wy.tcp;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
//接收端Socket对象
ServerSocket ss = new ServerSocket(10000);
//监听客户端的连接
Socket sk = ss.accept();
while (true) {
//接收端输入流获取数据
InputStream is = sk.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
//将获取到的数据在控制台输出
System.out.println(new String(buf, 0, len));
}
}
}
必须首先运行服务端,服务端进行监听,当监听到客户端的连接,则服务端开始读取数据。
下面是服务端将客户端发送来的数据写入文件:
package com.wy.tcpfile;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(20000);
Socket sk = ss.accept();
OutputStream os = new FileOutputStream("a.txt");
while(true){
InputStream is = sk.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
os.write(buf,0,len);
os.flush();
}
}
}
使用TCP协议完成文件上传功能:
其中客户端先读取文件,然后将数据写入到输出流中;
服务端开辟一个线程,用来接收数据,并将数据写入到一个文件中;
启动服务;
客户端代码:
package com.wy.tcpfileupload;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) throws Exception {
Socket sk = new Socket("192.168.20.5", 2000);
BufferedReader br = new BufferedReader(new FileReader("upload.txt"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
sk.getOutputStream()));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
sk.close();
}
}
服务端代码:
package com.wy.tcpfileupload;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.UUID;
public class TcpServerThread implements Runnable {
Socket sk;
public TcpServerThread(Socket sk) {
this.sk = sk;
}
@Override
public void run() {
String line;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
sk.getInputStream()));
BufferedWriter bw = new BufferedWriter(new FileWriter(UUIDTest.getFileName()));
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}
}
UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。这里使用UUID生成上传的文件的唯一id,进行保存。这样,即使上传的是同一个文件名,也会保存下来。
package com.wy.tcpfileupload;
import java.util.UUID;
public class UUIDTest {
public static String getFileName(){
String fileName = UUID.randomUUID().toString();
fileName = fileName.replaceAll("-", "")+".txt";
return fileName;
}
}
测试:
package com.wy.tcpfileupload;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(9999);
Socket sk = ss.accept();
new Thread(new TcpServerThread(sk)).start();
}
}