黑马程序员_Java网络编程

----------- android培训java培训java学习型技术博客、期待与您交流! ------------

 

        网络编程概述:

网络模型:

 

网络通讯要素:

1.IP地址(封装成InetAddress对象):网络中设备的标识。不易记忆,可用主机名。

本机回环地址:127.0.0.1     本机名:localhost

2.端口号:用于标识进程的逻辑地址,不同进程的标识。

有效端口:0-65535,其中0-1024系统使用或保留的端口。

3.传输协议:通讯的规则。常见的协议:TCP,UDP

UDP:将数据及源和目的封装成数据包中,不需要建立连接。每个数据包的大小限制在64K内。因无连接,是不可靠协议。不需要建立连接,速度快。

TCP:建立连接,形成传输数据的通道。在连接中进行大数据量传输。通过三次握手完成连接,是可靠协议。必须建立连接,效率稍低。

IP地址示例:

import java.net.*;
class IPDemo
{
 public static void main(String[] args)throws Exception
 {
  InetAddress i=InetAddress.getLocalHost();
  System.out.println(i.toString());
  System.out.println("address:"+i.getHostAddress());
  System.out.println("name:"+i.getHostName());
  InetAddress[] ias=InetAddress.getAllByName("192.168.1.106");
  for(InetAddress ia:ias)
  {
   System.out.println("address:"+ia.getHostAddress());
   System.out.println("name:"+ia.getHostName());
  }
 }
}

 

Socket:Socket就是为网络服务提供的一种机制。通讯的两端都有Socket。网络通讯其实就是Socket间的通讯。数据在两个Socket间通过IO传输。

 

UDP传输:

通过DatagramSocket与DatagramPacket对象,建立发送端与接受端。

建立数据包。

调用Socket的发送接收方法。

关闭Socket。

发送端和接收端是两个独立的应用程序。

定义一个UDP发送端,通过UDP传输方式,将一段文字数据发送出去。

发送端示例:

import java.net.*;
class UdpSend
{
 public static void main(String[] args)throws Exception
 {
  //1.创建UDP服务。通过DatagramSocket对象。
  DatagramSocket ds=new DatagramSocket(8888);
  //2.确定数据,并封装成数据包。
  byte[] buf="udp ge men lai le".getBytes();
  DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("61.190.87.111"),5000);
  //3.通过Socket服务,将已有的数据包发送出去。通过send方法。
  ds.send(dp);
  //4.关闭资源。
  ds.close();
 }
}

定义一个UDP接收端,用于接收UDP协议传输的数据并处理。

接收端示例:

import java.net.*;
class UdpRece
{
 public static void main(String[] args)throws Exception
 {
  //1.创建UDPSocket服务,建立端点。
  DatagramSocket ds=new DatagramSocket(5000);
  while(true)
  {
   //2.定义数据包,用于存储数据。
   byte[] buf=new byte[1024];
   DatagramPacket dp=new DatagramPacket(buf,buf.length);
   //3.通过UDPSocket服务的receive方法将收到的数据存入数据包中。
   ds.receive(dp);
   //4.通过数据包的方法获取其中的数据。
   String ip=dp.getAddress().getHostAddress();
   String data=new String(dp.getData(),0,dp.getLength());
   int port=dp.getPort();
   System.out.println(ip+"::"+data+"::"+port);
  }
  //5.关闭资源。
  //ds.close();
 }
}

将键盘录入方式的数据通过UDP传输。

示例:

import java.net.*;
import java.io.*;
class UdpSend2
{
 public static void main(String[] args)throws Exception
 {
  DatagramSocket ds=new DatagramSocket();
  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("61.190.87.255"),5001);
   ds.send(dp);
  }
  ds.close();
 }
}

//接收端

class UdpRece2
{
 public static void main(String[] args)throws Exception
 {
  DatagramSocket ds=new DatagramSocket(5001);
  while(true)
  {
   byte[] buf=new byte[1024];
   DatagramPacket dp=new DatagramPacket(buf,buf.length);
   ds.receive(dp);
   String ip=dp.getAddress().getHostAddress();
   String data=new String(dp.getData(),0,dp.getLength());
   System.out.println(ip+"::"+data);
  }
 }
}

 

编写一个聊天程序。用UDP传输。

分析:有收数据的部分和发数据的部分。这两部分需要同时执行。那就需要用到多线程技术。一个线程控制收,一个线程控制发。因为收和发动作是不一致的,所以要定义两个run方法。而这两个run方法要封装到不同的类中。

示例:

import java.net.*;
import java.io.*;
class Send implements Runnable
{
 private DatagramSocket ds;
 public 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("61.190.87.255"),5002);
    ds.send(dp);
   }
  }
  catch (Exception e)
  {
   throw new RuntimeException("发送端失败");
  }
 }
}

//接收端
class Rece implements Runnable
{
 private DatagramSocket ds;
 public Rece(DatagramSocket ds)
 {
  this.ds=ds;
 }
 public void run()
 {
  try
  {
   byte[] buf=new byte[1024];
   DatagramPacket dp=new DatagramPacket(buf,buf.length);
   ds.receive(dp);
   String ip=dp.getAddress().getHostAddress();
   String data=new String(dp.getData(),0,dp.getLength());
   System.out.println(ip+"::"+data);
  }
  catch (Exception e)
  {
   throw new RuntimeException("接收端失败");
  }
 }
}
class ChatDemo
{
 public static void main(String[] args)throws Exception
 {
  DatagramSocket sendSocket=new DatagramSocket();
  DatagramSocket receSocket=new DatagramSocket(5002);
  new Thread(new Send(sendSocket)).start();
  new Thread(new Rece(receSocket)).start();
 }
}

TCP传输:

通过Socket和ServerSocket对象,建立客户端和服务器端。

建立连接后,通过Socket中的IO流进行数据的传输。

关闭Socket。

客户端和服务器端是两个独立的应用程序。

创建TCP传输的客户端:

示例:

import java.net.*;
import java.io.*;
class TcpClient
{
 public static void main(String[] args)throws Exception
 {
  //1.创建客户端的Socket服务,指定目的主机和端口。
  Socket s=new Socket("61.190.87.111",5003);
  //2.为了发送数据,应该获取Socket流中的输出流。
  OutputStream out=s.getOutputStream();
  out.write("tcp ge men lai le".getBytes());
  //3.关闭客户端。
  s.close();
 }
}

定义服务端接收数据并打印在控制台上。

服务端示例:

import java.net.*;
import java.io.*;

class TcpServer
{
 public static void main(String[] args)throws Exception
 {
  //1.建立服务端Socket服务。并监听一个端口。
  ServerSocket ss=new ServerSocket(5003);
  //2.通过accept方法获取连接过来的客户端对象。
  Socket s=ss.accept();
  //3.获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
  InputStream in=s.getInputStream();
  byte[] buf=new byte[1024];
  int len=in.read(buf);
  String ip=s.getInetAddress().getHostAddress();
  System.out.println(ip+".....connected");
  System.out.println(new String(buf,0,len));
  //4.关闭客户端。
  s.close();
  //ss.close();
 }
}

 

演示TCP传输的客户端和服务端的互访。即客户端给服务端发送数据,服务端收到后,给客户端反馈信息。

客户端:

1.建立Socket服务,指定要连接的主机和端口。

2.获取Socket流中的输出流。将数据写到该流中,通过网络发送给服务端。

3.获取Socket流中的输入流,将服务端反馈的数据获取到,并打印。

4.关闭客户端资源。

客户端示例:

import java.net.*;
import java.io.*;
class TcpClient2
{
 public static void main(String[] args)throws Exception
 {
  Socket s=new Socket("61.190.87.111",5004);
  OutputStream out=s.getOutputStream();
  out.write("服务端,你好".getBytes());
  InputStream in=s.getInputStream();
  byte[] buf=new byte[1024];
  int len=in.read(buf);
  System.out.println(new String(buf,0,len));
  s.close();
 }
}

服务端示例:

import java.net.*;
import java.io.*;

class TcpServer2
{
 public static void main(String[] args)throws Exception
 {
  ServerSocket ss=new ServerSocket(5004);
  Socket s=ss.accept();
  String ip=s.getInetAddress().getHostAddress();
  System.out.println(ip+".....connected");
  InputStream in=s.getInputStream();
  byte[] buf=new byte[1024];
  int len=in.read(buf);
  System.out.println(new String(buf,0,len));
  OutputStream out=s.getOutputStream();
  out.write("哥们收到,你也好".getBytes());
  s.close();
  ss.close();
 }
}

 

演示用TCP传输上传文件:

示例:

import java.net.*;
import java.io.*;
class TextClient
{
 public static void main(String[] args)throws Exception
 {
  Socket s=new Socket("61.190.87.111",5006);
  BufferedReader bufr=new BufferedReader(new FileReader("IPDemo.java"));
  PrintWriter out=new PrintWriter(s.getOutputStream(),true);
  String line=null;
  while((line=bufr.readLine())!=null)
  {
   out.println(line);
  }
  s.shutdownOutput();
  BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
  String str=bufIn.readLine();
  System.out.println(str);
  bufr.close();
  s.close();
 }
}

//服务端
class TextServer
{
 public static void main(String[] args)throws Exception
 {
  ServerSocket ss=new ServerSocket(5006);
  Socket s=ss.accept();
  String ip=s.getInetAddress().getHostAddress();
  System.out.println(ip+"......connected");
  BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
  PrintWriter out=new PrintWriter(new FileWriter("server.txt"),true);
  String line=null;
  while((line=bufIn.readLine())!=null)
  {
   out.println(line);
  }
  PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
  pw.println("上传成功");
  out.close();
  s.close();
  ss.close();
 }
}

 

演示用TCP传输上传图片:

示例:

import java.net.*;
import java.io.*;
class PicClient
{
 public static void main(String[] args)throws Exception
 {
  Socket s=new Socket("61.190.84.248",5007);
  FileInputStream fis=new FileInputStream("D:\\TDDOWNLOAD\\亚洲pic\\0402080030234500.jpg");
  OutputStream out=s.getOutputStream();
  byte[] buf=new byte[1024];
  int len=0;
  while((len=fis.read(buf))!=-1)
  {
   out.write(buf,0,len);
  }
  s.shutdownOutput();
  InputStream in=s.getInputStream();
  byte[] bufIn=new byte[1024];
  int num=in.read(bufIn);
  System.out.println(new String(bufIn,0,num));
  fis.close();
  s.close();
 }
}

//服务端
class PicServer
{
 public static void main(String[] args)throws Exception
 {
  ServerSocket ss=new ServerSocket(5007);
  Socket s=ss.accept();
  String ip=s.getInetAddress().getHostAddress();
  System.out.println(ip+"......connected");
  InputStream in=s.getInputStream();
  FileOutputStream fos=new FileOutputStream("server.jpg");
  byte[] buf=new byte[1024];
  int len=0;
  while((len=in.read(buf))!=-1)
  {
   fos.write(buf,0,len);
  }
  OutputStream out=s.getOutputStream();
  out.write("上传成功".getBytes());
  fos.close();
  s.close();
  ss.close();
 }
}

演示客户端通过TCP传输并发上传图片:

示例:

import java.net.*;
import java.io.*;
class PicClient
{
 public static void main(String[] args)throws Exception
 {
  if(args.length!=1)
  { 
   System.out.println("请选择一个jpg格式的图片");
   return;
  }
  File file=new File(args[0]);
  if(!(file.exists()&&file.isFile()))
  {
   System.out.println("该文件有问题,要么不存在,要么不是文件");
   return;
  }
  if(!file.getName().endsWith(".jpg"))
  {
   System.out.println("图片格式错误,请重新选择");
   return;
  }
  if(file.length()>1024*1024*5)
  {
   System.out.println("文件太大,没安好心");
   return;
  }
  Socket s=new Socket("61.190.84.248",5008);
  FileInputStream fis=new FileInputStream(file);
  OutputStream out=s.getOutputStream();
  byte[] buf=new byte[1024];
  int len=0;
  while((len=fis.read(buf))!=-1)
  {
   out.write(buf,0,len);
  }
  s.shutdownOutput();
  InputStream in=s.getInputStream();
  byte[] bufIn=new byte[1024];
  int num=in.read(bufIn);
  System.out.println(new String(bufIn,0,num));
  fis.close();
  s.close();
 }
}
/*
服务端:这个服务端有个局限性。当A客户端连接上以后,被服务端获取到。服务端开始执行具体流程。
这时B客户端连接,只有等待。因为服务端还没有处理完A客户端的请求,没有循环回来执行下一次accept方法。所以暂时获取不到B客户端对象。
那么为了可以让多个客户端同时并发访问服务端,服务端最好就是将每个客户端封装到一个单独的线程中。这样,就可以同时处理多个客户端的请求。
如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可。将该代码存入run方法中。
*/
class PicThread implements Runnable
{
 private Socket s;
 PicThread(Socket s)
 {
  this.s=s;
 }
 public void run()
 {
  int count=1;
  String ip=s.getInetAddress().getHostAddress();
  try
  {
   System.out.println(ip+"......connected");
   InputStream in=s.getInputStream();
   File file=new File(ip+"("+(count)+")"+".jpg");
   while(file.exists())
    file=new File(ip+"("+(count++)+")"+".jpg");
   FileOutputStream fos=new FileOutputStream(file);
   byte[] buf=new byte[1024];
   int len=0;
   while((len=in.read(buf))!=-1)
   {
    fos.write(buf,0,len);
   }
   OutputStream out=s.getOutputStream();
   out.write("上传成功".getBytes());
   fos.close();
   s.close();
  }
  catch (Exception e)
  {
   throw new RuntimeException(ip+"上传图片失败");
  }
  
 }
}
class PicServer
{
 public static void main(String[] args)throws Exception
 {
  ServerSocket ss=new ServerSocket(5008);
  while(true)
  {
   Socket s=ss.accept();
   new Thread(new PicThread(s)).start();
  }
 }
}

演示客户端并发登录:

客户端通过键盘录入用户名。服务端对这个用户名进行校验。如果该用户名存在,在服务端显示xxx,已登录。并在客户端显示xxx,欢迎光临。

如果该用户名不存在,在服务端显示xxx,尝试登录。并在客户端显示xxx,该用户不存在。

最多就登录三次。

示例:

import java.net.*;
import java.io.*;
class LoginClient
{
 public static void main(String[] args)throws Exception
 {
  Socket s=new Socket("61.190.84.248",5009);
  BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
  PrintWriter out=new PrintWriter(s.getOutputStream(),true);
  BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
  for(int x=0;x<3;x++)
  {
   String line=bufr.readLine();
   if(line==null)
    break;
   out.println(line);
   String info=bufIn.readLine();
   System.out.println("info:"+info);
   if(info.contains("欢迎"))
    break;
  }
  bufr.close();
  s.close();
 }
}

//服务端
class UserThread implements Runnable
{
 private Socket s;
 UserThread(Socket s)
 {
  this.s=s;
 }
 public void run()
 {
  String ip=s.getInetAddress().getHostAddress();
  System.out.println(ip+".......connected");
  try
  {
   for(int x=0;x<3;x++)
   {
    BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
    String name=bufIn.readLine();
    if(name==null)
     break;
    BufferedReader bufr=new BufferedReader(new FileReader("user.txt"));
    PrintWriter out=new PrintWriter(s.getOutputStream(),true);
    String line=null;
    boolean flag=false;
    while((line=bufr.readLine())!=null)
    {
     if(line.equals(name))
     {
      flag=true;
      break;
     }
    }
    if(flag)
    {
     System.out.println(name+",已登录");
     out.println(name+",欢迎光临");
     break;
    }
    else
    {
     System.out.println(name+",尝试登录");
     out.println(name+",用户名不存在");
    }
   }
   s.close();
  }
  catch (Exception e)
  {
   throw new RuntimeException(ip+"校验失败");
  }
 }
}
class LoginServer
{
 public static void main(String[] args)throws Exception
 {
  ServerSocket ss=new ServerSocket(5009);
  while(true)
  {
   Socket s=ss.accept();
   new Thread(new UserThread(s)).start();
  }
 }
}

演示客户端和服务端:

1.客户端:浏览器。

   服务端:自定义。

示例:

import java.net.*;
import java.io.*;
class ServerDemo
{
 public static void main(String[] args)throws Exception
 {
  ServerSocket ss=new ServerSocket(5010);
  Socket s=ss.accept();
  System.out.println(s.getInetAddress().getHostAddress());
  InputStream in=s.getInputStream();
  byte[] buf=new byte[1024];
  int len=in.read(buf);
  System.out.println(new String(buf,0,len));
  PrintWriter out=new PrintWriter(s.getOutputStream(),true);
  out.println("<font color='red' size='6'>客户端你好</font>");
  s.close();
  ss.close();
 }
}

2.客户端:浏览器。

   服务端:Tomcat服务器。

用浏览器访问本机的Tomcat服务器的自定义的主页demo.html:http://localhost:8080/myweb/demo.html

 

3.客户端:自定义。

   服务端:Tomcat服务器。

示例:

import java.net.*;
import java.io.*;
class MyIE
{
 public static void main(String[] args)throws Exception
 {
  Socket s=new Socket("61.190.85.20",8080);
  PrintWriter out=new PrintWriter(s.getOutputStream(),true);
  out.println("GET /myweb/demo.html HTTP/1.1");
  out.println("Accept:*/*");
  out.println("Accept-Language:zh-cn");
  out.println("Host:61.190.85.20:5010");
  out.println("Connection:closed");
  out.println();
  out.println();
  BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
  String line=null;
  while((line=in.readLine())!=null)
  {
   System.out.println(line);
  }
  s.close();
 }
}

 

URL对象中的常见方法:

String getFile()
          获取此 URL 的文件名。
 String getHost()
          获取此 URL 的主机名(如果适用)。
 String getPath()
          获取此 URL 的路径部分。
 int getPort()
          获取此 URL 的端口号。
 String getProtocol()
          获取此 URL 的协议名称。
 String getQuery()
          获取此 URL 的查询部分。

示例:

import java.net.*;
class URLDemo
{
 public static void main(String[] args)throws MalformedURLException
 {
  URL url=new URL("http://61.190.85.20:8080/myweb/demo.html?name=wanglin&age=20");
  System.out.println("getProtocol():"+url.getProtocol());
  System.out.println("getHost():"+url.getHost());
  System.out.println("getPort():"+url.getPort());
  System.out.println("getPath():"+url.getPath());
  System.out.println("getFile():"+url.getFile());
  System.out.println("getQuery():"+url.getQuery());
 }
}

 

URLConnection:内部包含了http协议,可将服务端发给客户端的信息头解析拆包,只将信息主体显示出来。

示例:

import java.net.*;
import java.io.*;
class URLConnectionDemo
{
 public static void main(String[] args)throws Exception
 {
  URL url=new URL("http://61.190.85.20:8080/myweb/demo.html");
  URLConnection conn=url.openConnection();
  System.out.println(conn);
  InputStream in=conn.getInputStream();
  byte[] buf=new byte[1024];
  int len=in.read(buf);
  System.out.println(new String(buf,0,len));
 }
}

 

域名解析:http://主机名,要将主机名翻译成IP地址,需要到DNS服务器进行域名解析。

例如:http://www.sina.com.cn

www.sina.com.cn进行域名解析的过程:

1.先找本地的hosts文件(该文件位于c:\windows\system32\drivers\ext\hosts),查找其对应的IP地址。

2.hosts文件中没有,再到DNS服务器去找对应的IP地址。

3.都没找着,提示域名不可用。

 

----------- android培训java培训java学习型技术博客、期待与您交流! ------------

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值