您的位置:首页 > 理论基础 > 计算机网络

Java——网络编程

2015-08-18 15:07 477 查看
网络编程
在网络中发送数据分几个步骤:
1、首先要找到对方IP
2、要发到指定的应用程序上 就要对应用程序进行数字标识,这些标识叫做端口
3、定义通讯规则,称为协议,国际通用协议是TCP/IP协议,但不是唯一协议

所以网络通讯要素有三:
1、IP地址
2、端口号
3、传输协议

网络模型:
OSI模型:
从上至下依次是:应用层 -> 表示层 -> 会话层 -> 传输层 -> 网络层 -> 数据链路层 -> 物理层
TCP/IP模型:
从上至下依次是:应用层 -> 传输层 -> 网际层 -> 主机至网络层

IP地址:
IP地址是网络中设备的标识
不易记忆,可用主机名
本地回路地址:127.0.0.1 主机名:localhost

对应的java类是InetAddress类
InetAddress类

没有构造函数,通过静态方法getLocalHost()方法获取本类对象。
常用方法:
getByname(String host) //通过IP地址或主机名获取主机
getHostAddress() //获取IP地址的字符串形式
getHostName() //获取主机名
示例:
import java.net.*;

class IPDemo
{
<span style="white-space:pre">	</span>public static void main(String[] args)throws UnknownHostException
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>InetAddress ip = InetAddress.getLocalHost();
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>System.out.println(ip.toString());
<span style="white-space:pre">		</span>System.out.println(ip.getHostAddress());
<span style="white-space:pre">		</span>System.out.println(ip.getHostName());
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>InetAddress ips[] = InetAddress.getAllByName("www.google.com");
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>for(InetAddress i : ips)
<span style="white-space:pre">			</span>System.out.println(i.getHostAddress());
<span style="white-space:pre">	</span>}
}


UDP协议:
特点是:面向无连接,速度快,不可靠。
使用方法是通过DatagramSocket类建立对象,再使用DatagramPacket对象将要发送的数据封装进数据包对象,然后使用DatagramSocket对象的send()方法发送,
同时指定端口和目的主机。

下面是发送端和接收端的代码示例:
发送端:
import java.io.*;
import java.net.*;

class UdpSend
{
public static void main(String[] args)throws SocketException,UnknownHostException,IOException
{
//1、通过DatagramSocket对象 创建Udp对象
DatagramSocket ds = new DatagramSocket();

//2、确定数据 封装成数据包 DategramPacket(byte[] buf, int length,
//										 InetAddress address, int port)
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));

String line = null;
while((line = bufr.readLine()) != null)
{
if(line.equals("88"))
break;
byte[] buf = line.getBytes();
DatagramPacket dp =
new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.103"), 12322);

//3、通过socket服务 将已有数据包发送出去 通过send方法
ds.send(dp);
}
//4、关闭资源
ds.close();
}
}
接收端:
<pre name="code" class="html">import java.io.*;
import java.net.*;
class UdpRece{public static void main(String[] args)throws SocketException,UnknownHostException,IOException{DatagramSocket ds = new DatagramSocket(12322);while(true){//1、通过DatagramSocket对象 创建Udp对象//2、定义数据包 用于存储byte[]
buf = new byte[1024];DatagramPacket dp = new DatagramPacket(buf, buf.length);//3、通过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 ChatDemo
{
public static void main(String[] args)throws Exception
{
DatagramSocket sendSock = new DatagramSocket();
DatagramSocket receSock = new DatagramSocket(22233);

new Thread(new Rece(receSock)).start();
new Thread(new Send(sendSock)).start();
}

}

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(line.equals("end"))
break;
byte[] buf = line.getBytes();
DatagramPacket dp =
new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 11112 );

ds.send(dp);
}
ds.close();
}catch(Exception e)
{
throw new RuntimeException("send failed");
}
}
}

class Rece implements Runnable
{
private DatagramSocket ds;
public Rece(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
while(true)
{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);

ds.receive(dp);
String data = new String(dp.getData(), 0, dp.getLength());
String ip = dp.getAddress().getHostAddress();
System.out.println(data);
}
}catch(Exception e)
{
throw new RuntimeException("reveive failed");
}
}
}


TCP协议:
特点:面向连接,通过三次握手确立连接,速度较慢,可靠性高。
使用Tcp协议,必须明确客户端和服务端,客户端使用Socket类,并在构造方法中指定目的主机地址和端口号。
服务器端使用ServerSocket类,并用accept()方法接受一个Socket对象,建立连接后,才可以传输数据。

常用方法有:
getInputStream() //获取Socket对象的输入流
getOutputStream() //获取Socket对象的输出流

示例:

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

class TcpClient
{
public static void main(String[] args)throws Exception
{
//创建客户端Socket,指定目的主机 端口
Socket s = new Socket("169.254.90.177", 10003);

//为了发送数据,应该获取Socket流中的输出流
OutputStream out = s.getOutputStream();
out.write("tcp data".getBytes());

s.close();
}
}

class TcpServer
{
public static void main(String[] args)throws Exception
{
//创建服务端Socket 绑定端口
ServerSocket ss = new ServerSocket(10003);

//通过accept()方法获取连接过来的客户端流对象
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));
}


练习:客户端接收键盘录入信息发送给服务端,服务端将其转成大写再反馈给客户端

代码:
import java.io.*;
import java.net.*;

class TClient
{
public static void main(String[] args)throws Exception
{
//发送
Socket s = new Socket("169.254.90.177", 23333);
OutputStream out = s.getOutputStream();

BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine()) != null)
{
if(line.equals("over"))
break;
out.write(line.getBytes());

//接收反馈
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String rData = new String(buf, 0, len);
System.out.println(rData);

}

s.close();
}
}

class TServer
{
public static void main(String[] args)throws Exception
{
//接收
ServerSocket ss = new ServerSocket(23333);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "  connected");
InputStream in;
OutputStream out;
while(true)
{
in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String data = new String(buf, 0, len);
if(data.equals("over"))
break;
//反馈
String rData = data.toUpperCase();
out = s.getOutputStream();
out.write(rData.getBytes());
}
}
}


模拟实际应用:上传图片:
客户端将本地图片发送给服务端,服务端反馈“接收成功”。
需要注意的是,服务端应能完成同时接收多个客户端同时上传的操作,所以每接收到一个客户端Socket,都将其封装成一个线程,才能实现同时接收。
代码如下:
import java.net.*;
import java.io.*;

class ThreadClient
{
public static void main(String[] args)throws Exception
{
if(args.length != 1)
{
System.out.println("wrong path");
return;
}

File file = new File(args[0]);
if(! (file.exists() && file.isFile()))
{
System.out.println("wrong file");
return;
}
if(! file.getName().endsWith(".jpg"))
{
System.out.println("wrong file format");
return;
}
if(file.length() > 1024 * 1024 * 3)
{
System.out.println("file too large");
return;
}

Socket s = new Socket("169.254.90.177", 23335);
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 lenIn = 0;
lenIn = in.read(bufIn);
System.out.println(new String(bufIn, 0, lenIn));

s.close();
}
}

class ThreadServer
{
public static void main(String[] args)throws Exception
{
ServerSocket ss = new ServerSocket(23335);

while(true)
{
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
}
}

class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s)
{
this.s = s;
}
public void run()
{
String ip = s.getInetAddress().getHostAddress();
try
{
int count = 1;
System.out.println(ip + "  connected");

File file = new File(ip + "(" + count + ")" + ".jpg");
while(file.exists())
file = new File(ip + "(" + count++ + ")" + ".jpg");
InputStream in = s.getInputStream();
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("file received".getBytes());
}
catch(Exception e)
{
throw new RuntimeException(ip +"  upload failed");
}
}
}


实际应用2:实现多用户登陆功能。
建立一张用户名表,客户端接收键盘录入,发送给服务端,服务端查询用户名表,如果存在则返回登陆成功,否则返回失败,一个IP最多失败三次,然后禁止登陆。
代码:

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

class LoginClient
{
public static void main(String[] args)throws IOException
{
Socket s = new Socket("169.254.90.177", 23338);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);

BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

String line = null, info = null;
for(int i = 0; i < 3; i++)
{
line = bufr.readLine();
if(line == null)
break;
out.println(line);

info = bufIn.readLine();

System.out.println("info: " + info);
if(info.contains("welcome"))
break;
}

s.close();
bufr.close();
}
}

class UserThread implements Runnable
{
private Socket s;
public UserThread(Socket s)
{
this.s = s;
}
public void run()
{
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + ".. connected");
try
{
for(int i = 0; i < 3; i ++)
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String name = bufr.readLine();
if(name == null)
break;

BufferedReader bufIn = new BufferedReader(new FileReader("user.txt"));
String line = null;

PrintWriter out = new PrintWriter(s.getOutputStream(), true);

boolean found = false;
while((line = bufIn.readLine()) != null)
{
if(line.equals(name))
{
found = true;
break;
}
}

if(found == true)
{
System.out.println(name + "  login");
out.println("welcome  " + name );
break;
}else
{
System.out.println(name + "  try to login");
out.println(name + "  name not found");
}

}

s.close();
}catch(Exception e)
{
throw new RuntimeException(ip + "  check failed");
}
}
}

class LoginServer
{
public static void main(String[] args)throws IOException
{
ServerSocket ss = new ServerSocket(23338);

while(true)
{
Socket s = ss.accept();

new Thread(new UserThread(s)).start();
}

}
}


自定义服务端,接收来自浏览器的请求并返回信息给浏览器。
代码:
import java.net.*;
import java.io.*;

class ServerDemo
{
public static void main(String[] args)throws IOException
{
ServerSocket ss = new ServerSocket(10086);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress() + "..connected");

PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("hello client");

}
}


URL

URL全称是uniform resource locator,中文是统一资源定位器,是资源的一种标识。
对应的类是URL。
常用方法:
构造函数:URL(String protocol,String host,int port,String file);//指定 protocol、host、port号和 file

String getProtocol() //获取协议名称

String getHost() //获取主机名

int getPort() //获取端口号

String getFile() //获取URL文件名

String getPath() //获取此URL的路径部分

String getQuery() //获取此URL的查询部,客户端传输的特定信息

示例:
import java.net.*;
import java.io.*;

class URLDemo
{
public static void main(String[] args)throws MalformedURLException
{
URL url = new URL("http://169.254.90.177:8080/myweb/demo.html");

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());

}
}


域名解析:

在浏览器地址栏中输入一个域名时,浏览器会首先在本地host文件中查询对应的IP,如果存在则直接访问,如果不存在,就请求网络供应商,访问对方的DNS服务器。
DNS服务器中存储的是大量的IP和域名的映射表,再通过映射表找到对应IP,访问对应服务器。

-----------android培训java培训、java学习型技术博客、期待与您交流!------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: