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

网络编程——Java基础

2015-07-09 02:19 585 查看
一、网络编程概述

网络编程参考模型:OSI模型和TCP/IP模型。

通讯的要素:

IP地址:网络中设备的标识,本地回环地址127.0.0.1,主机名:localhost.

端口号:英语标识进程的逻辑地址,即不同进程的标识,有效端口号为:0~65535,

其中0~1024为系统保留。

传输协议:即通信规则,有UDP、TCP.

代码实例:演示获取主机名,根据主机名获取IP

class IPDemo
{
public static void main(String [] args)
{
InetAddress i = InetAddress.getByName("www.baidu.com");
System.out.println(i.toString());
System.out.println("name: "+i.getHostName());
System.out.println("address: "+i.getHostAddress());
}
}
UDP:

将数据以及源和目的封装成数据包中,不需要建立连接。

每个数据包大小限制在60k以内。

因为不需要建立连接,是不可靠协议。

无需连接,速度较快

TCP:

建立连接形成数据传输通道。

在连接中进行大数据量传输。

通过三次握手建立连接,可靠协议。

必须要建立连接,效率稍低。

Socket:

为网络服务提供的一种机制。

通信两端都有Socket

网络通信其实就是Socket间通信。

数据在两个Socket之间通过IO传输。

二、使用UDP建立接收和发送端

重点在于掌握UDP的接收端和发送端的建立流程。

定义UDP发送端步骤:

1.建立udpsocket服务。

2.提供数据并将数据封装到数据包中。

3.通过socket服务的发送功能将数据包发送出去。

4.关闭资源。

定义UDP接收端步骤:

定义UDP接收端

1.定义udpsocket服务。通常会监听一个端口,其实就是给这个接收网络

应用程序定义一个数字标识,方便明确哪些数据过来

该应用程序可以处理

2.定义一个数据包,因为要存储接收到的字节数据,因为数据包对象中

3.通过socket服务的receive方法将受到的数据存入已经定义好的数据包中

4.通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台。

5.关闭资源。

代码实例:UDP发送端

import java.net.*;
class UdpSend
{
public static void main(String[] args) throws Exception
{
//创建udp服务。通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket();

//2.确定数据,并封装成数据包。
byte[] buf="ge men lai le".getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.102"),123);

//3.通过socket服务将已有的数据包发送出去。通过send方法
ds.send(dp);

//4.关闭资源。
ds.close();

}
}
代码实例:UDP接收端

class UdpRec
{
public static void main(String[] args) throws Exception
{
//1.创建udp socket。建立端点
DatagramSocket ds=new DatagramSocket(123);

while(true)
{
//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();
}

}
}
对以上的发送和接收服务端稍加改造,可以实现一个简单的聊天程序

示例代码:

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

class  UdpSend2
{
public static void main(String[] args) throws Exception
{
//创建UDP服务对象
DatagramSocket ds=new DatagramSocket();
//键盘录入信息
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

String line=null;
while((line=bufr.readLine())!=null)
{
//结束发送标志
if("88".equals(line))
break;
byte[] buf=line.getBytes();

//打包
DatagramPacket dp=
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.102"),10001);

ds.send(dp);
}
//关闭资源
ds.close();
}
}

class UdpRec2
{
public static void main(String [] args)throws Exception
{
//创建接收端对象并监听端口。
DatagramSocket ds=new DatagramSocket(10001);

//阻塞
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);

}
}
}
三、TCP传输

TCP分为客户端和服务端,客户端对应的对象时Socket,

服务端对应的对象时ServerSocket.

客户端:

在建立Socket对象时就可以去连接指定主机。

因为TCP是面向连接的。所以在建立Socket服务时。

就要有服务端存在。并连接成功。形成通路

在该同道中进行数据传输。

客户端步骤:

1.创建Socket服务。并制定要连接的主机和端口。

2.为了发送数据。应该获取socket流中的输出流。

3.将数据写入到获取的输出流中

4.关闭资源

服务端:

1.建立服务端的socket服务。ServerSocket();

并监听一个端口

2.获取链接过来的客户端对象。

通过ServerSocket的accept方法。这个方法

是阻塞式的。

3.客户端发过来数据。服务端使用对应的客户端对象

并获取到该客户端的读取流。

并打印在控制台。

4.关闭服务端(可选)

客户端示例代码:带反馈信息

class TcpClient
{
public static void main(String[] args)throws Exception{
//建立客户端服务,制定主机和端口号
Socket s = new Socket("192.168.0.102",10001);
//获取输出流
OutputStream out = s.getOutputStream();
//将数据写入到获取的输出流中
out.write("Tcp Demo".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();
}
}
服务端示例代码:接收成功给客户端返回信息

class TcpServer
{
public static void main(String[] args)throws Exception{
//建立服务端,监听端口号。
ServerSocket ss = new ServerSocket(10001);
//接收链接过来的客户端对象
String s = ss.accept();
//获取一下客户端IP并打印
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"*****connect");
//使用对应的客户端获取该客户端的读取流
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("Server Accepted Data ok!".getBytes());
//关闭资源
s.close();
//ss.close();

}
}
示例代码:客户端键盘录入字母发送给服务端,服务端转换成大写,反馈给客户端

package Net;
import java.net.*;
import java.io.*;

//创建客户端,键盘录入信息,传给服务端,并接收服务端反馈的信息
class TransClient {
public static void main(String[] args)throws Exception{
//创建客户端服务,指定主机和端口号
Socket s = new Socket("192.168.0.102",10011);
//读取键盘录入.源
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;
while((line = bufr.readLine())!=null)
{
//检测到over就结束
if(line.equals("over"))
break;
//将读到的键盘录入信息写入到已经关联的输出流。
out.println(line);
//获取服务端返回的信息并打印
String str = bufIn.readLine();
System.out.println("server: "+str);

}
bufr.close();
s.close();
}
}
//创建服务端,接收客户端发送过来的信息,进行大写转换后,反馈。
class TransServer{
public static void main(String[] args)throws Exception{
//创建服务端,监听端口号
ServerSocket ss = new ServerSocket(10011);
//接收并打印客户端IP
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"************is connected");
//获取流中的数据。源
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//关联输出流,目的
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//进行读取
String line = null;
while((line = bufIn.readLine())!=null)
{
System.out.println(line);
//将接收的数据进行大写转换并写到已关联的输出流
out.println(line.toUpperCase());
}
s.close();
}
}
使用TCP协议,从客户端向服务端传送一个文件。大体思路与上例相似,只不过客户端的源由原来的键盘录入改为

关联一个需要上传的文件,但是注意:传送文件结束标记要用:shutdownOutput();方法。相当于给流一个-1的结束标志;

而服务端的源依然是输入流,目的则改为磁盘,存储客户端传送过来的文件,其实相当于将文件内容复制过来。

具体实现代码如下:

/*
需求:客户端文件内容发送给服务端
并在服务端保存(相当于copy)
*/

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

class  TextClient
{
public static void main(String[] args) throws Exception
{
//创建客户端,指定主机和端口号,关联源和目的。
Socket s=new Socket("192.168.0.102",10009);
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);
}
//关闭客户输出流,相当于给流加了一个结束标记-1.
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
{
//创建服务端监听端口号获取并打印链接过来的主机IP
ServerSocket ss=new ServerSocket(10009);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+":::connect");
//创建输入流,关联目的
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();
}
}
并发访问服务端实例:客户端在控制台指定一个规定格式的文件上传到服务端,

且可以实现多个客户端同时上传。这就用到了多线程,将每个连接过来的客户端都封装成一个

对象,用该对象创建一个线程,而每个线程要执行的代码是相同的,可以将该代码写在run方法

中,

代码实例:

/*
需求:上传图片。
在控制台指定需要上传的文件。

*/

/*
客户端:
1.服务端点
2.读取客户端已有的图片数据
3.通过socket输出流将数据发给服务端。
4.读取服务端反馈信息。
5.关闭
*/
import java.net.*;
import java.io.*;
class  PicClient
{
public static void main(String[] args) throws Exception
{
//客户端读取已有图片(待定文件)源
FileInputStream fis=new FileInputStream(file);
//在客户端指定要选择的文件的格式要求。
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;
}
//如果指定文件满足格式要求,创建服务端点 IP Port
Socket s=new Socket("192.168.0.102",10010);
//创建输出字节流。目的
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 PicThread implements Runnable
{
//需要传入一个对象
private Socket s;
PicThread(Socket s)
{
this.s=s;
}
public void run()
{
//获取该对象的主机名
String ip=s.getInetAddress().getHostAddress();
try
{
int count=0;
System.out.println(ip+"****connect");
//数据输入读取流
InputStream in=s.getInputStream();
//多次上传命名
File file=new File(ip+"("+(count)+")"+".jpg");
while(file.exists())//如果已经存在就让count加1再存储。
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)
{
//写入数据到ser.bmp
fos.write(buf,0,len);
}
//给客户端反馈信息
OutputStream out=s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"获取失败");
}
}
}
/*服务端:
为了同时处理多个客户端的请求。将每个客户端封装到一个单独的
线程中,这样就可以同时处理多个客户请求
如何定义线程呢?
只要明确了每一个客户端要在服务端执行的代码即可,将该代码
存入run方法中。*/
class PicServer
{
public static void main(String[] args) throws Exception
{
//建立服务 监控端口号
ServerSocket ss=new ServerSocket(10010);
while(true)
{
//等待获取客户端,将接收到的客户端封装成对象,
Socket s=ss.accept();
//将接收到的客户端对象创建线程,(每接收一个对象就创建一个线程,实现并发访问)
new Thread(new PicThread(s)).start();
}
//ss.close();
}
}
四、浏览器作为客户端,服务端:自定义和Tomcat服务器

示例代码:

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

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

//获取客户端数据
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='7'>客户端你好</font>");

s.close();
ss.close();
}
}
五、小知识

关于InetAddress和InetSocketAddress的区别:

InetAddress代表IP地址,InetSocketAddress代表的IP+port。

域名解析:

想要将主机名翻译成ip地址,就需要域名解析,DNS.

域名和ip的映射关系存放在本机的C:\Windows\System32\drivers\etc\host文件中,

我们可以更改恶意网站域名对应的IP来达到避免被恶意网站感染。

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 url=new URL("http://192.168.0.102:8080/myweb/demo.html?haha&hello=90");
//解析
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());

//		int port=url.getPort();
//		返回-1则指定默认端口
//		if(port==-1)
//			port=80;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: