------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
网络编程概述:
要素:ip地址,端口号,传输协议
模型:OSI参考模型,TCP/IP参考模型
网络模型:
应用层:数据表现规律,及应用层的特征
TCP UDP在传输层。
IP地址协议在网络层。
数据链路层:底层传输协议。
物理层:网线
数据封包:加上每一层的特有信息。
数据传输就是通过数据封包,拆包这样完成的。
IP地址:
package Socket;
import java.net.InetAddress;
public class IPTest {
public static void main(String[] args)throws Exception{
//互联网协议的地址
InetAddress[] in=InetAddress.getAllByName("www.baidu.com");//获得百度的所有IP地址
for(InetAddress i:in){
String s=i.getHostName();//获得主机名
String ss=i.getHostAddress();//获得主机ip
System.out.println(s+"...."+ss);
}
}
}
TCP与UDP:
UDP:
1、将数据的源和目的封装成数据包,不需要建立连接
2、每个数据包的大小限制在64k内
3、因为是无连接,是不可靠协议。
4、不需要建立连接,故此速度快-----如视频会议,桌面共享,游戏,QQ
TCP:
1、要建立连接,形成传输数据的通道
2、在连接中进行大数据量传输。
3、通过3次握手完成连接,是可靠协议
4、必须建立连接,速度慢,效率稍低------电话,下载。
UDP发送端:
需求:通过udp传输,将一段文字数据发送出去
思路:
1.建立udpSocket服务。
2.提供数据,并将数据封装到数据包中
3.通过socket服务的发送功能,经数据包发送出去。
4.关闭资源。
package Socket;
import java.net.*;
public class UDPSocket {
public static void main(String[] args)throws Exception{
//创建udp服务
DatagramSocket ds=new DatagramSocket();
//确定数据,封装成数据包
byte[] buf="udp coming ".getBytes();
//将数据发送到制定的地址的指定端口上
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),1000);
//发送数据包
ds.send(dp);
//关闭资源
ds.close();
}
}
UDP接收端:
需求:定义一个应用程序用于接收udp协议传输的数据并处理。
思路:
1、定义udpSocket服务,通常会监听一个端口,方便明确数据是由哪个应用程序处理。
2、定义一个数据包,因为要存储接收到的字节数组。
3、通过socket服务的receive方法接收到的数据存到已定义好的数据包中。
4、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。
5、关闭资源。
package Socket;
import java.net.*;
public class UDPSocket {
public static void main(String[] args)throws Exception{
//创建udp服务
DatagramSocket ds=new DatagramSocket();
//确定数据,封装成数据包
byte[] buf="udp coming ".getBytes();
//将数据发送到制定的地址的指定端口上
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),1000);
//发送数据包
ds.send(dp);
//关闭资源
ds.close();
}
}
UDP键盘录入:
package Socket;
import java.io.*;
import java.net.*;
public class UDPSend {
public static void main(String[] args)throws Exception{
//udp服务
DatagramSocket ds=new DatagramSocket();
//定义输入流---字节流变字符流
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
//读数据
String line=null;
while((line=br.readLine())!=null){
if("886".equals(line))
break;
byte[] buf=line.getBytes();//字符串变字节
//将数据打包,存到那个ip地址,那个端口号下的
DatagramPacket dp=new DatagramPacket(buf,buf.length,ds.getInetAddress().getLocalHost(),1000);
//传输数据
ds.send(dp);
}
ds.close();
}
}
package Socket;
import java.net.*;
public class UDPResc {
public static void main(String[] args)throws Exception{
//udp服务,和发送端的端口关联好
DatagramSocket ds=new DatagramSocket(1000);
//定义数据包,用于存储数据
while(true){
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//存数据
ds.receive(dp);
String ip=dp.getAddress().getHostName();//获得次ip的主机名
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println(ip+"..."+data+"..."+port);
}
}
}
TCP传输:
客户端:
通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。因为tcp是面向连接的,所以在连建立socket服务时,就要有服务端存在,并连接成功,形成通路,在该通路上进行数据传输。
服务端:
1、建立服务端的socket服务,ServerSocket.并监听一个端口。
2、获取连接过来的服务端对象。通过serverSocket的accept方法,这是阻塞式方法.
3、客户端如果发送数据,服务端就要使用对应的客户端对象,并获取到该客户端的读取流来读数据。
一个简单的客户端、服务端程序:
package Socket;
import java.net.*;
import java.io.*;
public class Client{
public static void main(String[] args)throws Exception{
//建立Socket连接,并指定ip和端口
Socket s=new Socket("127.0.0.1",1000);
//获得客户端的读写流
OutputStream out=s.getOutputStream();
//写入数据
out.write("TCP Coming".getBytes());
//关闭客户端
s.close();
}
}
package Socket;
import java.net.*;
import java.io.*;
public class Srever {
public static void main(String[] args)throws Exception{
//建立服务端socket,并监听一个端口
ServerSocket ss=new ServerSocket(1000);
//通过accept方法获得客户端
Socket s=ss.accept();
//获得对应客户端读取流
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=0;
while((len=in.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
s.close();
}
}
练习:
客户端发送数据,服务端接收,反馈数据。
package Socket;
import java.net.*;
import java.io.*;
public class ClientDemo {
public static void main(String[] args)throws Exception{
Socket s=new Socket("127.0.0.1",1000);
//发送数据的输入流
OutputStream out=s.getOutputStream();
out.write("我来了".getBytes());
//读完客户的反馈数据
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=0;
len=in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
package Socket;
import java.net.*;
import java.io.*;
public class ServerDemo {
public static void main(String[] args)throws Exception{
ServerSocket ss=new ServerSocket(1000);
//获得客户端
Socket s=ss.accept();
//获得读取流
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=0;
len=in.read(buf);
System.out.println(new String(buf,0,len));
//获得写入流,输入反馈信息
OutputStream out=s.getOutputStream();
out.write("welcome !".getBytes());
s.close();
}
}
要求:客户端给服务端发送文本,服务端会将其转换成大写返回给客户端,而且客户端可以不断的进行文本转换,当客户端输入over时。转换结束。
分析:
客户端:源-操作文本---字符流
目的---网络设备---网络输出流。
步骤:
1、建立客户端,要在控制台上输入数据,要有一个与控制台关联的输入流。
2、为了给服务端发送数据,要有一个客户端的写入流。
3、为了读取服务端的反馈数据,要有一个客户端的读取流。
4、建立服务端,为了读服务端的发来的数据,要有一个对应客户端的读取流
5、服务端要把数据反馈给客户端,因此要有一个对应客户端的输入流。
注意:由于客户端中readLine是阻塞式方法。
package Socket;
import java.net.*;
import java.io.*;
public class Client{
public static void main(String[] args)throws Exception{
//建立Socket连接,并指定ip和端口
Socket s=new Socket("127.0.0.1",1000);
//获得客户端的读写流
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));//控制台的读取
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));//网络的读取
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
//从控制台上读数据,写数据
String line=null;
while((line=bufr.readLine())!=null){//readLine是阻塞式方法,它会一直等待控制台的输入
if("over".equals(line))
break;
pw.println("client:"+line);
String str=br.readLine();//从服务端读大写数据
System.out.println(str);
}
//关闭客户端
s.close();
br.close();
pw.close();
}
}
package Socket;
import java.net.*;
import java.io.*;
public class Srever {
public static void main(String[] args)throws Exception{
//建立服务端socket,并监听一个端口
ServerSocket ss=new ServerSocket(1000);
//通过accept方法获得客户端
Socket s=ss.accept();
//获得对应客户端读取流
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));//读网络数据
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
//读数据,把读到的数据变大写
String line=null;
while((line=br.readLine())!=null){
System.out.println(line);
pw.println(line.toUpperCase());//把大写数据发送给客户端
}
br.close();
pw.close();
s.close();
}
}
步骤:
客户端:
1、读取流与要复制的文件相关联
2、获得客户端写入流,把文件发送给服务端
3、获取客户端读取流,从服务端反馈的数据
服务端:
1、和一个写入流文件关联,作为目标文件
2、获得客户端读取流,读取客户端发来的数据,将其写到目标文件
3、获得客户端写入流,给客户端反馈数据。
package Socket;
import java.net.*;
import java.io.*;
public class TCPClient {
public static void main(String[] args)throws Exception{
Socket s=new Socket("127.0.0.1",1000);
BufferedReader br=new BufferedReader(new FileReader("e:/TCPClient.java"));
//上传,写入流
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
String line=null;
while((line=br.readLine())!=null){
pw.println(line);
}
s.shutdownOutput();//将流至于末尾 ...关闭客户端的输出流
//读取反馈
BufferedReader bs=new BufferedReader(new InputStreamReader(s.getInputStream()));
String str=bs.readLine();
System.out.println(str);
br.close();
s.close();
}
}
package Socket;
import java.net.*;
import java.io.*;
public class TCPServer {
public static void main(String[] args)throws Exception{
ServerSocket ss=new ServerSocket(1000);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
//读客户端发来的数据
BufferedReader bs=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter p=new PrintWriter(new FileWriter("e:/copy.txt"),true);
String line=null;
while((line=bs.readLine())!=null){
p.println(line);//注意:这里是免刷新的
}
//反馈给客户端数据
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
pw.println("上传成功");
s.close();
}
}
客户端并发上传图片:
多个客户端对一个服务器同时发送数据,那么把对客户的操作放在多线程的run方法中。
package Socket;
import java.io.*;
import java.net.*;
/*
* 多个客户端向同一个服务端发送数据。
* 用多线程方式定义多个客户端,然后把数据的读取操作放在run方法中.
*/
public class BmpClient {
public static void main(String[] args)throws Exception{
System.out.println(args[0]);
if(args[0].length()<1){
System.out.println("请选择一张图片:");
}
//参数作为文件目录
File file=new File(args[0]);
if(!(file.exists()&&file.isFile())){
System.out.println("你所选择的文件有问题,要么不是文件,要么文件不存在");
}
if(file.length()>5*1024*1024){
System.out.println("你选的文件过大,不是图片");
}
if(!(file.getName().endsWith(".bmp"))){
System.out.println("你选的不是.bmp规定格式的文件");
}
Socket s=new Socket("127.0.0.1",1000);
//得到读取流和文件向关联
InputStream in=new FileInputStream(file);
//得到客户端写入流
OutputStream sout=s.getOutputStream();
//从文件中读取图片
int len=0;
byte[] buf=new byte[1024];
while((in.read(buf))!=-1){
sout.write(buf);//写入文件
sout.flush();
}
//输出流关闭
s.shutdownOutput();
//定义读取流,读服务端反馈数据
InputStream sin=s.getInputStream();
byte[] b=new byte[1024];
int num=sin.read(b);
System.out.println(new String(b,0,num));
s.close();
in.close();
}
}
package Socket;
import java.io.*;
import java.net.*;
public class BmpServer {
public static void main(String[] args)throws Exception{
ServerSocket ss=new ServerSocket(1000);
//连接多个客户端
while(true){
//一个服务端和多个客户端连接
Socket s=ss.accept();
new Thread(new PICServer(s)).start();
}
}
}
class PICServer implements Runnable{
Socket s;
OutputStream out=null;
String ip;
public PICServer(Socket s){
this.s=s;
}
public void run() {
int count=0;
try{
//IP地址
ip=s.getInetAddress().getHostAddress();
//目的文件路径
File file=new File("e:/"+ip+"("+count+")"+".bmp");
while(file.exists()){
file=new File("e:/"+ip+"("+(count++)+")"+".bmp");
}
//定义一个写入流和目标文件关联
out=new FileOutputStream(file);
//得到客户端读取流
InputStream sin=s.getInputStream();
int len=0;
byte[] buf=new byte[1024];
while((len=sin.read(buf))!=-1){
out.write(buf);
out.flush();
}
//给客户端反馈数据
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
pw.write("上传成功");
pw.flush();
s.close();
}catch(Exception e){
System.out.println(ip+"上传文件失败");
}finally{
try{
out.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
运行结果:
客户端并发登录:
要求:只运行3次登录机会,如果该用户还是不存在,那么久不能继续登录了。
package Socket;
import java.io.*;
import java.net.*;
/*
* 多个客户端进行用户登录,一个用户只有3次机会进行登录
* 从一个文件从当数据库,校验用户名
* 多线程来实现多用户登录。
*/
public class LoginClient {
public static void main(String[] args)throws Exception{
Socket s=new Socket("127.0.0.1",1000);
//控制台输入用户名
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
//获得客户端的写入流
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
//有3次机会可以登录
for(int i=0;i<3;i++){
System.out.println("请输入用户名:");
String name=br.readLine();
if(name.equals(null)){
System.out.println("请输入用户名");
}
//把用户名发送到服务端去
pw.println(name);
//读取服务端反馈
BufferedReader sb=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=sb.readLine();
System.out.println(line);
if(line.contains("欢迎")){
break;//已近登录的用户,不用3次机会了
}
}
s.close();
br.close();
}
}
package Socket;
import java.io.*;
import java.net.*;
public class LoginServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(1000);
while (true) {
Socket s = ss.accept();
new Thread(new User(s)).start();
}
}
}
class User implements Runnable {
Socket s;
private boolean flag = false;
public User(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 sbr = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 和用户明文件关联
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream("e:/user.txt")));
// 进行校验
String line = sbr.readLine();
System.out.println(line + "......");
String name = null;
while ((name = br.readLine()) != null) {
if (name.equals(line)) {
flag = true;
break;
}
}
// 反馈给服务端信息
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
if (flag) {
pw.println(line + "欢迎登录");
break;
} else {
pw.println(line + "用户名不存在");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
自定义浏览器:
浏览器都会给服务器发送请求消息头,因此自定义的浏览器也要给服务器发送那些数据。
请求头:
代码:
package Socket;
import java.io.*;
import java.net.*;
public class MyIE {
public static void main(String[] args)throws Exception{
Socket s=new Socket("127.0.0.1",8080);
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
pw.println("GET / HTTP/1.1");
pw.println("Accept: */*");
pw.println("Accept-Language: zh-CN,zh;q=0.8");
pw.println("Host: localhost:11000");
pw.println("Connection: keep-alive");
pw.println();
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=br.readLine())!=null){
System.out.println(line);
}
s.close();
}
}