---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
一、网络编程概述:
1、网络模型
OSI参考模型与TCP/IP参考模型
2、网络通讯要素
1)IP地址
网络中设备的标识;
不易记忆,可用主机名;
本地回环地址:127.0.0.1;主机名:localhost。
InetAddress ia=InetAddress.getByName("www.baidu.com");
System.out.println(ia.getHostAddress());
System.out.println(ia.getHostName());
输出结果:
111.13.100.91
www.baidu.com
2)端口号
用于标识进程的逻辑地址;
端口的取值范围:0-65535。
常见的端口:网络服务(Web服务)为80;QQ聊天有两个端口,4000端口用于接收QQ状态信息的数据包,8080端口用于接收我们发送的聊天信息;FTP服务为21(20)。
3)传输协议
通讯规则。常见协议:TCP、UDP
UDP:
不需要建立连接;将数据及源和目的都封装在数据包中;每个数据包的大小限制在64K内;因为是无连接,所以是不可靠协议;也因此速度快。
TCP:
建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;也因此,效率稍低。
二、UDP传输
Socket:
Socket就是为网络服务提供的一种机制,通信两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
例1:定义UDP发送端,将一段文字数据发送出去
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SendSocket {
public static void main(String[] args)throws Exception{
//通过DatagramSocket对象,创建UDP服务
DatagramSocket ds=new DatagramSocket();
//确定数据,并封装成数据包
byte[] buf="udp chuan shu".getBytes();
DatagramPacket dp=
new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8080);
//通过Socket的send方法,将已有的数据包发送出去
ds.send(dp);
//关闭资源
ds.close();
}
}
例2:定义UDP接收端,接收UDP协议传输的数据并处理
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class ReceiveSocket {
public static void main(String[] args) throws Exception{
//创建UDP socket,监听端点
DatagramSocket ds=new DatagramSocket(8080);
while(true){
//定义数据包,用于存储数据
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//通过receive方法将收到的数据存入数据包
ds.receive(dp);//阻塞式方法
//通过数据包的方法获取其中的数据
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
}
//ds.close();
}
}
例3:编写一个简易聊天程序
需求:有收数据部分与发数据部分,两部分需同时进行。因此需要多线程技术。
package com.cn.itcast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class UDPChatTest {
public static void main(String[] args) throws Exception{
DatagramSocket sendSocket=new DatagramSocket();
DatagramSocket receSocket=new DatagramSocket(8081);
new Thread(new Send(sendSocket)).start();
new Thread(new Receive(receSocket)).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("886".equals(line)) //当键盘录入"886"时,停止聊天
break;
byte[] buf=line.getBytes();
DatagramPacket dp=
new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8081);
ds.send(dp);
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Receive implements Runnable{
private DatagramSocket ds;
public Receive(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 ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+":"+data);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三、TCP传输
通过Socket和ServerSocket建立客户端和服务器端。建立连接后,通过Socket中的IO流进行数据的传输。同样,客户端与服务器端是两个独立的应用程序。
例4:客户端向服务器端发送一个文本数据,服务器端接收数据后打印在控制台上
客户端:
/*
*通过查询socket对象,发现该对象建立时就可以去连接指定主机。
*因为TCP是面向连接的,所以建立客户端socket服务时,就要有服务器端存在并连接成功。
*形成通路后,在该通道进行数据的传输。
*/
package com.cn.itcast;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
public static void main(String[] args) {
try {
//创建客户端的socket,指定目的主机和端口
Socket s=new Socket("127.0.0.1",8082);
//获取socket中的输出流,用于发送数据
OutputStream out=s.getOutputStream();
out.write("TCP chuanshu".getBytes());
s.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
服务器端:
package Com.cn.ItCast;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) {
try {
//建立服务端socket,并监听一个端口
ServerSocket ss=new ServerSocket(8082);
//通过accept方法获取连接过来的客户端对象
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"....isconnected");
//获取客户端对象的读取流,用于读取客户端发送来的数据
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();//关闭客户端
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
例5:建立一个文本转换服务器
需求:客户端给服务器端发送文本,服务器端会将文本转换成大写后返回给客户端。客户端可以不断地进行文本转换,直到客户端输入“over”时,转换结束。
客户端:
package com.cn.itcast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class TransClient {
public static void main(String[] args)throws Exception {
Socket s=new Socket("127.0.0.1",8083);
//建立读取流,读取键盘录入的数据
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
//建立socket写入流,将读取到的键盘录入数据发送到服务器端
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//建立socket读取流,读取从服务器端发来的转换后的文本数据
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null){
out.write(line);
//必须加换行符,否则服务器端的readLine方法无法读到换行符,就不能返回数据
out.newLine();
out.flush();//刷新,将数据刷至服务器端
//读取从服务器端发来的数据
String str=in.readLine();
System.out.println("server:"+str);
}
bufr.close();
s.close();
}
}
服务器端:
package com.cn.itcast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TransServer {
public static void main(String[] args) throws Exception{
ServerSocket ss=new ServerSocket(8083);
Socket s=ss.accept();
//建立socket读取流,读取从客户端发来的文本数据
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
//建立socket写入流,将服务器端转换了的文本数据发送给客户端
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line=null;
//若客户端发送数据后不添上换行符,readLine方法将不断读取数据却不返回
while((line=in.readLine())!=null){
out.write(line.toUpperCase());
out.newLine();
out.flush();
}
s.close();
ss.close();
}
}
注意:服务器端与客户端的out对象若改为:PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
这时,while循环里out的三句代码可简化为:pw.println(line.toUpperCase());
例6:客户端并发上传图片
客户端:
package com.cn.itcast;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public 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"))){ //确保文件格式为JPG
System.out.println("图片格式错误!");
return;
}
if(file.length()>1024*1024*5){ //确保文件大小不超过上限
System.out.println("文件过大,超过上传上限!");
return;
}
//建立各种流
Socket s=new Socket("127.0.0.1",8085);
FileInputStream fis=new FileInputStream(file);//获取本地文件读取流,用于读取本地图片
OutputStream out=s.getOutputStream();//获取Socket的写入流,用于将图片数据发送给服务器端
InputStream in=s.getInputStream();//获取Socket的读取流,用于读取服务器端返回的消息
//读取本地图片并发送给服务器端
byte[] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1){
out.write(buf,0,len);
}
s.shutdownOutput();//告诉服务器端数据已写完
fis.close();
//获取服务器端返回消息
byte[] bufIn=new byte[1024];
int num=in.read(bufIn);
System.out.println(new String("服务器端返回消息:"+new String(bufIn,0,num)));
s.close();
}
}
服务器端:
package com.cn.itcast;
import java.net.ServerSocket;
import java.net.Socket;
public class PicServer {
public static void main(String[] args) throws Exception{
ServerSocket ss=new ServerSocket(8085);
//并发处理各个客户端
while(true){
Socket s=ss.accept();
new Thread(new PicThread(s)).start();//对于每个客户端,都建立相应的线程来处理
}
}
}
线程:
package com.cn.itcast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class PicThread implements Runnable {
private Socket s;
PicThread(Socket s){
this.s=s;
}
@Override
public void run() {
int count=1;
String ip=s.getInetAddress().getHostAddress();//获取客户端IP地址
System.out.println(ip+"...is connected");
try {
InputStream in=s.getInputStream();//创建Socket的读取流,用于读取客户端发来的数据
//按"ip(n).jpg"格式创建不重名文件
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();//创建Socket写入流,用于返回消息
out.write((ip+":上传成功!").getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
例7:自定义图形化浏览器
/*
*例7:自定义图形化浏览器
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class GUIBrowser
{
public static void main(String[] args)throws Exception
{
Frame f=new Frame("主窗体");
f.setBounds(500,400,300,200);
f.setLayout(new FlowLayout());
Button b=new Button("转到按钮");
final TextField tf=new TextField(60);
final TextArea ta=new TextArea(25,70);
f.add(b);
f.add(tf);
f.add(ta);
//窗体关闭
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
//按下转到指定网页
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//清屏
ta.setText("");
//通过获得的url地址,截取IP地址、端口及路径
String urlPath=tf.getText();//http://192.168.1.101:11000
int index=urlPath.indexOf("//")+2;
String str=urlPath.substring(index);
String[] arr=str.split(":");
String IP=arr[0];
int port=Integer.parseInt(arr[1]);
try
{
//建立Socket及Socket的写入流,向服务器发送数据
Socket s=new Socket(IP,port);
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
//利用out向Tomcat服务器发送请求消息头
out.println("GET /HTTP/1.1");
out.println("Accept:*/*");
out.println("Accept-Language:zh-cn");
out.println("Host:192.168.1.101:11000");
out.println("Connection:closed");
out.println();//请求消息头与请求消息体的分隔空行
//建立Socket的读取流,读取服务器返回的数据并显示在ta文本框内
BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null)
{
ta.append(line+"\r\n");
}
s.close();
}
catch (Exception ex)
{
System.out.println(ex.toString());
}
}
});
//按下回车键也转到指定网页
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
{
ta.setText("");
String urlPath=tf.getText();
int index=urlPath.indexOf("//")+2;
String str=urlPath.substring(index);
String[] arr=str.split(":");
String IP=arr[0];
int port=Integer.parseInt(arr[1]);
try
{
Socket s=new Socket(IP,port);
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("GET /HTTP/1.1");
out.println("Accept:*/*");
out.println("Accept-Language:zh-cn");
out.println("Host:192.168.1.101:11000");
out.println("Connection:closed");
out.println();
BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null)
{
ta.append(line+"\r\n");
}
s.close();
}
catch (Exception ex)
{
System.out.println(ex.toString());
}
}
}
});
f.setVisible(true);
}
}
例8:URL
import java.net.URL;
class URLTest
{
public static void main(String[] args) throws Exception
{
//URL可以根据指定的协议、IP地址、端口号建立
URL url=new URL("http://192.168.1.101:11000/mywbe/demo.html?name=haha&&age=30");
//URL的几个重要get方法
System.out.println("getFile():"+url.getFile());
System.out.println("getHost():"+url.getHost());
System.out.println("getPath():"+url.getPath());
System.out.println("getPort():"+url.getPort());
System.out.println("getProtocol():"+url.getProtocol());
System.out.println("getQuery():"+url.getQuery());
}
}
/*
String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getProtocol()
获取此 URL 的协议名称。
String getQuery()
获取此 URL 的查询部分。
*/
输出结果:
getFile():/mywbe/demo.html?name=haha&&age=30
getHost():192.168.1.101
getPath():/mywbe/demo.html
getPort():11000
getProtocol():http
getQuery():name=haha&&age=30
例9:URLConnection
import java.net.URL;
class URLConnectionTest
{
public static void main(String[] args)
{
URL url=new URL("http://192.168.1.101:11000");
URLConnection conn=url.openConnection();//通过该方法与服务器建立连接
System.out.println(conn);
InputStream in=conn.getInputStream();//获取读取流,读取从服务器发来的数据
byte[] buf=new byte[1024];
int len=0;
System.out.println(new String(buf,0,len));
}
}
四、DNS(Domain Name System)
DNA服务器,又叫域名解析服务器。
DNS功能:
每个IP地址都可以有一个主机名,主机名由一个或多个字符串组成,字符串之间用小数点隔开。有了主机名,就不用死记硬背每台IP设备的IP地址,只要记住相对直观有意义的主机名就行了。这就是DNS协议所要完成的功能。
主机名到IP地址的映射有两种方式:
1)静态映射,每台设备上都配置主机到IP地址的映射,各设备独立维护自己的映射表,而且只供本设备使用;
2)动态映射,建立一套域名解析系统(DNS),只在专门的DNS服务器上配置主机到IP地址的映射,网络上需要使用主机名通信的设备,首先需要到DNS服务器查询主机所对应的IP地址。
通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。设备支持在本地进行主机名解析,也支持通过DNS进行域名解析。在解析域名时,首先采用静态域名解析的方法,如果静态域名解析不成功,再采用动态域名解析的方法。可以将一些常用的域名放入静态域名解析表中,这样可以大大提高域名解析效率。
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com