------- android培训、java培训、期待与您交流! ----------
day24***tcp***************************************************
@@TCP 传输
1,Socket和ServerSocket
2,建立客户端和服务器端
3,建立连接后,通过Socket中的IO流进行数据的传输。
4,关闭Socket
5,客户端和服务器端是两个独立的应用程序。
@@Socket类用来创建tcp协议的客户端
此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
构造方法
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket()
通过系统默认类型的 SocketImpl 创建未连接套接字
{用下面的函数进行连接服务器端!
void connect(SocketAddress endpoint)
将此套接字连接到服务器。
void connect(SocketAddress endpoint, int timeout)
将此套接字连接到服务器,并指定一个超时值。
}
Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
方法摘要
InetAddress getInetAddress()
返回套接字连接的地址。(即对方的地址)
InputStream getInputStream()
返回此套接字的输入流。
OutputStream getOutputStream()
返回此套接字的输出流。
int getPort()
返回此套接字连接到的远程端口。
void shutdownInput()
此套接字的输入流置于“流的末尾”。
void shutdownOutput() //关闭输出流。相当于给流中加入一个结束标记-1.让对方知道输出流已结束!
禁用此套接字的输出流。
void close()
关闭此套接字。
@@ServerSocket类用来创建tcp协议的服务器端
此类实现服务器套接字。服务器套接字等待请求通过网络传入。
它基于该请求执行某些操作,然后可能向请求者返回结果。
构造方法
ServerSocket()
创建非绑定服务器套接字。
{用下面方法完成绑定指定客户端
void bind(SocketAddress endpoint)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
void bind(SocketAddress endpoint, int backlog)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
}
ServerSocket(int port)
创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog) //backlog最大连接个数,一般是50
利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr)
使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
方法摘要
Socket accept()
侦听并接受到此套接字的连接。
InetAddress getInetAddress()
返回此服务器套接字的本地地址。
int getLocalPort()
返回此套接字在其上侦听的端口。
例1 从客户端发送一次数据到服务器端,服务端反馈一次信息。
import java.io.*;
import java.net.*;
class TcpClient//客户端发送一段数据给服务器端
{
public static void main(String[] args)throws Exception
{
//创建客户端的socket服务。指定目的主机和端口
Socket s = new Socket("127.0.0.1",10003);
//为了发送数据,应该获取socket流中的输出流。
OutputStream out = s.getOutputStream();
out.write("shuju".getBytes());
s.close();
}
}
class TcpServer
{
public static void main(String[] args)throws Exception
{
ServerSocket ss = new ServerSocket(10003);//监听端口
//通过accept方法获取连接过来的客户端对象。
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip);
//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
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();
s.close();//服务端不关自己,但会关闭客户端.
}
}
}
例 2 @@从客户端发数据给服务端,服务端返回数据的大写!
import java.io.*;
import java.net.*;
class TcpClient
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("127.0.0.1",10004);
//客户端的数据来源!
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
//创建Socket的IO流!
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//还可以PrintWriter PWout = new PrintWriter(s.getOutputStream(),true);
//true代表调用println、printf 或 format方法时,自动刷新!
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null)//客户端的数据
{
if("over".equals(line))
break;
out.write(line);//将数据发给服务端!
out.newLine();//记得加结束标记!
out.flush();//记得刷新!
//还可以PWout.println(line);
//接受服务器返回的数据!
String str = in.readLine();
System.out.println("服务端返回的数据:"+str);
}
bufr.close();
s.close();//在Socket流中加了-1,即结束标记!
}
}
class TcpServer
{
public static void main(String[] args)throws Exception
{
ServerSocket ss = new ServerSocket(10004);
Socket s = ss.accept();
//看客户端连接上了吗?
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"连接上了");
//创建Socket的IO流!
BufferedReader in =
new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//还可以PrintWriter PWout = new PrintWriter(s.getOutputStream(),true);
//true代表调用println、printf 或 format方法时,自动刷新!
String line = null;
while((line=in.readLine())!=null)//读取客户端发来的数据
{
out.write(line.toUpperCase());//将数据处理后,再发给客户端
out.newLine();//记得结束标记!
out.flush();//记得刷新!
//还可以PWout.println(line);
}
s.close();
ss.close();
}
}
/*
该例子出现的问题。
现象:客户端和服务端都在莫名的等待。
为什么呢?
因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等
而导致两端,都在等待。
*/
例 3
@@并发上传图片
import java.net.*;
import java.io.*;
class PicClient
{
public static void main(String[] args)throws Exception
{
if(args.length!=1)
{
System.out.println("请选择一个图片文件");
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("文件太大,要少于5M");
return ;
}
Socket s = new Socket("127.0.0.1",10006);
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();
}
}
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+".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();
//ss.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"上传失败");
}
}
}
class PicServer
{
public static void main(String[] args)throws Exception
{
ServerSocket ss = new ServerSocket(10006);
while(true)
{
Socket s = ss.accept();
new Thread(new PicThread(s)).start();
}
}
}
例 4 @@登录检验 userLogin
import java.io.*;
import java.net.*;
class LoginClient
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",10008);
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
BufferedReader in =
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 = in.readLine();
System.out.println("info:"+info);
if(info.contains("欢迎"))
break;
}
}
}
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(10008);
while (true)
{
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}
@@客户端和服务端
/*
演示客户端和服务端。
1,
客户端:浏览器 dos下: telnet 目的主机ip 端口号
服务端:自定义。
2,
客户端:浏览器。 http//127.0.0.1:8080/myweb(资源路径)/demo.html(资源) 请求服务器的哪些网页
服务端:Tomcat服务器。
D:\apache-tomcat-6.0.30\webapps\myweb
信息网页包 放在webapps包 下面
3,
客户端:自定义。(图形界面)
服务端:Tomcat服务器。
*/
import java.net.*;
import java.io.*;
class ServerDemo
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);
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();
}
}
/**浏览器给服务端发送的信息。http的请求消息头。
http://127.0.0.1:11000/myweb/demo.html(地址栏的数据)
协议://主机名 :端口号/资源路径/资源
1(重) GET /myweb/demo.html HTTP/1.1(协议版本,还有个1.0)(请求行必须有)
2(重) Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave
-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msw
ord, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xps
document, application/xaml+xml, */*(其他的也都支持,可以只写这个)(浏览器支持的东西)
3(重) Accept-Language: zh-cn(接受中文版)
4 User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET
CLR 2.0.50727; InfoPath.3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)(用户信息)
5 Accept-Encoding: gzip, deflate(支持的封装形式:gzip压缩,)
6(重) Host: localhost:11000(服务器我要访问的你的xx主机:端口)(服务器上可以有很多主机)
7 Connection: Keep-Alive(连接状态)
(空行隔开)==必须
请求数据体
...
...
*/
class MyIE
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",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: localhost:11000");
out.println("Connection: Keep-Alive");//另一个状态 :closed
out.println();//一定写空行****************一定要有!
out.println();
BufferedReader bufr =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line=bufr.readLine())!=null)
{
System.out.println(line);
}
s.close();
}
}
/*MyIE发过去的 http请求数据头!
GET /myweb/demo.html HTTP/1.1
Accept: */*
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET
CLR 2.0.50727; InfoPath.3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Accept-Encoding: gzip, deflate
Host: localhost:11000
Connection: Keep-Alive
(空行)**************************一定有的!
请求数据体
*/
/*服务器返回来的 http应答数据头!
HTTP/1.1 200(响应状态码) OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"221-1345432552000"
Last-Modified: Mon, 20 Aug 2012 03:15:52 GMT
Content-Type: text/html
Content-Length: 221
Date: Mon, 20 Aug 2012 04:03:14 GMT
Connection: close
*/
@@URL 封装了socket对象到 URLConnection对象中!
import java.net.*;
class URLDemo
{
public static void main(String[] args) throws MalformedURLException
{
URL url =
new URL("http://127.0.0.1/myweb/demo.html?name=haha&age=30 ");
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();
if(port==-1)//默认为-1
port=8080;*/
}
}
/*
String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getProtocol()
获取此 URL 的协议名称。
String getQuery()
获取此 URL 的查询部分。
*/
class URLConnectionDemo 这个类是将MyIE类中的内容封装了!
{
public static void main(String[] args) throws Exception
{
URL url =
new URL("http://127.0.0.1:8080/myweb/demo.html?name=haha&age=30 ");
URLConnection conn = url.openConnection();
//不用写socket,已经连接并封装了,从传输层 到 应用层了!响应头被处理了。
//只显示需要的资源
System.out.println(conn);
//相当于 socket中的方法 s.getInputStream();
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
}
}
@@域名解析
http://www.baidu.com:8080/myweb/demo.html(地址栏的数据)
想要将主机名www.baidu.com 翻译成ip地址 需要域名解析,需要DNS域名解析服务器。
浏览器先去公网上找一台DNS,然后找到与百度对应的ip地址,获取该地址。
DNS上都是 网站和 ip地址的 键值对,映射表。
DNS将ip返回给客户机(浏览器),客户机再通过
http://69.5.64.2:8080/myweb/demo.html(地址栏的数据)
来去请求 百度的 网页信息。
其实浏览器最先寻找的是本地记录的信映射表信息。
对于http://127.0.0.1:8080/myweb/demo.html(地址栏的数据)
本地主机有 本地DNS 即本地记录的 域名解析服务器。
c:\windows\system32\drivers\etc中有hosts文件 存有映射关系。
咱自己可以在文件中添加一些映射关系,
1--来避免一些软件去它的官网更新(它想检查你的注册码的正确性)
127.0.0.1 它的官网
2--来添加 127.0.0.1 木马网站 来避免木马网站修改IE主页。