要学好网络编程首先要了解网络通讯相关的知识
1.网络通信的要素
[1],找到对方IP地址
[2],指明要发送数据的端口
[3],遵守通信规则, TCP/IP协议
2.理解关键术语
[1] IP地址:网络中设备的标识,由于ip地址不易记忆,可用主机名代替如:www.buaidu.com。本机的ip地址为主机名为:localhost
本地回环地址:127.0.0.1
[2] 端口号:用于标识进程的额逻辑地址,不同进程的标识.有效端口:0~~65535,其中0~1024一般为系统使用或保留端口,只有知道端口号,我们才知道自己要将信息传输给主机上的哪个程序。
[3] 传输协议
(1) UDP---面向无连接
特点:
<1>.将数据及源和目的封装在数据包中,不需要建立连接
<2>.每个数据包的大小限制在64K内
<3>.因为无连接,所以UDP是不可靠协议
<4>应为不需要建立连接,所以速度快
(2) TCP----面向连接
特点:
<1>.建立连接,形成传输数据的通道
<2>.可以进行大量数据传输
<3>.通过三次握手完成连接,是可靠协议
<4>.由于必须建立连接,所以效率会稍低
通过java编程更深入学习网络编程
提到Java的网络编程不得不了解Socket,网络编程就是Socket编程
Socket(套接字)
1,Socket就是为网络服务提供的一种机制
2,通信两端都有必须有Socket
3,数据在两个Socket间通过IO传输
UDP
项目小实践:通过udp传输方式,将一段文字数据发送出去。,
写一个udp发送端。
思路:
1,建立updsocket服务。
2,提供数据,并将数据封装到数据包中。
3,通过socket服务的发送功能(getOutputStream),将数据包发出去。
4,关闭资源。
eg:
class UdpSend{
public static void main(String[] args)throws Exception{
//1
DatagramSocket ds = new DatagramSocket(8808);
//2
byte[] data = "My Name KCH".getBytes();
DatagramPacket dp = new DatagramPacket(data,data.length,InetAddress.getByName("localhost"),8086);
//3
ds.send(dp);
//4
ds.close();
}
}
这样 My Name KCH就发送到所以和本机连接的主机上去了
项目小实践2:接收udp协议传输的数据并处理。
写一个udp的接收端。
思路:
1,定义udpsocket服务
2,定义一个数据包,要存储接受到的字节数据,数据包中有更多功能提取字节数据中的不同数据信息
3,通过socket服务的receive方法将接受到的数据存入数据包中。
4,通过数据包中的方法获取不同数据。
5,关闭资源
eg:class UdpRece{
public static void main(String[] args)throws Exception{
//1
DatagramSocket ds = new DatagramSocket(8086);
//2
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data,data.length);
//3
ds.receive(dp);//阻塞式方法,有数据就执行,没数据就等
//4
String ip = dp.getAddress().getHostAddress();
String datas = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+"--"+port+"--"+datas);
//5
ds.close();
}
}
掌握了以上udp网络编程的技术后我们就可以写一个自己山寨版的qq了。
思路:
由于聊天是双向的并且一个程序能发送数据也能接受数据,所以我们要在一个程序中写一个发送端一个接受端,并让他们同是工作,那么就要用到多线程技术了,运行是两个动作分别为两个线程,并同时工作,所以要用两个类分别封装发送端和接受端。两个类都要实现Runnable接口
eg:项目小实践3:MyQQ
class Send implements Runnable{
private DatagramSocket ds;
Send(DatagramSocket ds){
this.ds = ds;
}
public void run(){
try{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine())!= null){
if("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.137.255"),10000);
ds.send(dp);
}
ds.close();
}catch(Exception e){
System.out.println("send exception");
}
}
}
class Rece implements Runnable{
private DatagramSocket ds;
Rece(DatagramSocket ds){
this.ds = ds;
}
public void run(){
try{
byte[] buf = new byte[1024];
while(true){
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String datas = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(ip+" "+port+" "+datas);
}
}catch(Exception e){
System.out.println("rece exception");
}
}
}
class Chat{
public static void main(String[] args) throws Exception{
DatagramSocket ds_send = new DatagramSocket(8064);
DatagramSocket ds_rece = new DatagramSocket(10000);
new Thread(new Send(ds_send)).start();
new Thread(new Rece(ds_rece)).start();
}
}
TCP
tcp分为客户端和服务端。
客户端对应的对象是Socket
服务端对应的对象是ServerSocket
TCP----->客户端
通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。如:new Socket(“www.baidu.com“,8086)就是连接了百度服务器的8086端口。
因为tcp是面向连接的。所以在建立socket服务时,就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
穿件客户端的步骤:
1,建立socket服务。指定要连接主机和端口。
2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
3,获取socket流中的输入流,将服务端反馈的数据获取到。
4,关闭客户端资源
eg:
class Client{
public static void main(String[] args)throws Exception{
//创建一个连接到192.168.137.1主机的8084端口上的socket连接
Socket s = new Socket("100.64.182.196",8086);
//定义读取键盘输入的流对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//定义一个目的,将数据写入soket输出流发给服务端
PrintWriter priw_socket = new PrintWriter(s.getOutputStream(),true);
//定义一个socket读取流,读取服务端返回的数据
BufferedReader bufr_socket = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufr.readLine())!= null){
if("over".equals(line))
break;
priw_socket.println(line);
System.out.println("server:"+bufr_socket.readLine());
}
s.close();
bufr.close();
}
}
TCP--->服务端
建立服务端的步骤:
1,建立服务端的socket服务。ServerSocket(); ,并监听一个端口。
2,获取连接过来的客户端对象。 通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法是阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
4,关闭服务端(可选)
eg:class Server{
public static void main(String[] args)throws Exception{
ServerSocket ss = new ServerSocket(8086);
Socket s = ss.accept();
//定义一个目的,将socket大写数据写入到socket输出流并发送个客户端
PrintWriter priw_socket = new PrintWriter(s.getOutputStream(),true);
//读取socket流中读取的数据
BufferedReader bufr_socket = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufr_socket.readLine())!= null){
System.out.println(line);
priw_socket.println(line.toUpperCase());
}
s.close();
ss.close();
}
}
掌握了以上tcp的技术我们就可以完成一系列小项目了
eg:项目实践4:多客户端并发上传文件,这就用到了多线程
class Client{
public static void main(String[] args)throws Exception{
if(args.length != 1){
System.out.println("no file");
return;
}
File file = new File(args[0]);
if(!(file.exists() && file.isFile())){
System.out.println("file erro of notexist");
return;
}
if(file.length()>1024*1024*4){
System.out.println("file is too big");
return;
}
Socket s = new Socket("100.64.182.196",8086);
FileInputStream fis = new FileInputStream(file);
OutputStream os = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf))!= -1){
os.write(buf,0,len);
}
s.shutdownOutput();
InputStream is = s.getInputStream();
int num = 0;
byte[] buf_in = new byte[1024];
num = is.read(buf_in);
System.out.println(new String(buf_in,0,num));
fis.close();
s.close();
}
}
class Server_Thread implements Runnable{
private Socket s;
Server_Thread(Socket s){
this.s = s;
}
public void run(){
String ip = s.getInetAddress().getHostAddress();
try{
System.out.println(ip+".....connect");
InputStream is = s.getInputStream();
File file = new File(ip+".jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf))!= -1){
fos.write(buf,0,len);
}
OutputStream os = s.getOutputStream();
os.write("send picture seccessful".getBytes());
fos.close();
s.close();
}catch(Exception e){
throw new RuntimeException("erro");
}
}
}
class Server{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(8086);
while(true){
Socket s = ss.accept();
new Thread(new Server_Thread(s)).start();
}
}
}
运行结果:一张图片被上传到指定位置
eg:项目实践5多客户端并发登录
class Client{
public static void main(String[] args)throws Exception{
Socket s = new Socket("100.64.182.196.",8080);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
BufferedReader bufr_socket = new BufferedReader(new InputStreamReader(s.getInputStream()));
for(int i = 0;i<=2;i++){
String line = bufr.readLine();
if(line == null)
break;
pw.println(line);
String info = bufr_socket.readLine();
System.out.println(info);
if(info.contains("login succeed"))
break;
}
s.close();
bufr.close();
}
}
class Server_Thread implements Runnable{
private Socket s;
Server_Thread(Socket s){
this.s = s;
}
public void run(){
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...connect");
try{
for(int i=0;i<3;i++){
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
BufferedReader bufr_file = new BufferedReader(new FileReader("a.txt"));
String str = null;
String str_Client = bufr.readLine();
if(str_Client == null)
break;
boolean flag = false;
while((str = bufr_file.readLine())!= null){
if(str_Client.equals(str)){
flag = true;
break;
}
}
if(flag){
System.out.println(str_Client+" had login");
pw.println(str_Client+" login succeed");
break;
}
else{
System.out.println(str_Client+" try to login");
pw.println(str_Client+" is no exist");
}
}
s.close();
}catch(Exception e){
throw new RuntimeException("server error");
}
}
}
class Server{
public static void main(String[] atgs)throws Exception{
ServerSocket ss = new ServerSocket(8080);
while(true){
Socket s = ss.accept();
new Thread(new Server_Thread(s)).start();
}
}
}
运行结果: