网络基础知识
IP地址:每个网卡都有一个或多个IP地址;
而IP地址类型有两种,一种是IPV4,一种是IPV6;
通过在命令提示符输入ipconfig可以查询本机的IP地址;
本机的保留IP是127.0.0.1;
端口(port):
相当于服务器的码头,每个客户端连接进来都需要确切的端口;
公网和内网
网络是按层次划分的,最外层是公网,而底下每一层都是内网,
而UDP和TCP通讯协议是在传输层;
TCP:
传输控制协议,面向连接两台机器可靠无差错的数据传输,为双向字节流传递。
UDP:
用户数据报协议,面向无连接不保证可靠的数据传输。
URL
统一资源定位符,表示某一资源的地址
通常由协议名称和资源名称组成,中间用冒号隔开,如:
http://www.baidu.com
http为超文本传输协议,后面的//www.baidu.com为资源名称
URL这个类在java.net.URL这个包中
通过URL读取网页页面内容
public static void main(String[] args) {
try {
URL url=new URL("http://www.baidu.com");
InputStream is=url.openStream();
InputStreamReader ir=new InputStreamReader(is,"UTF-8");//读取文本用reader;字符输入流包装
BufferedReader br=new BufferedReader(ir);//字符输入流缓冲,提高读取效率
String data=br.readLine();
while (data!=null) {
System.out.println(data);
data=br.readLine();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
基于TCP协议的网络编程
1.服务器:创建一个ServerSocket,等待连接;
2.客户端:创建一个Socket,连接到服务器;
3.服务器:ServerSocket接收到连接,创建一个Socket和客户的 Socket建立专线连接,后续服务器和客户机的对话(这一对Socket) 会在一个单独的线程(服务器端)上运行;
4.服务器的ServerSocket继续等待连接,返回1.
ServerSocket: 服务器码头
–需要绑定port
–如果有多块网卡,需要绑定一个IP地址
• Socket: 运输通道
–客户端需要绑定服务器的地址和Port
–客户端往Socket输入流写入数据,送到服务端 –客户端从Socket输出流取服务器端过来的数据 –服务端反之亦然
服务端等待响应时,处于阻塞状态
• 服务端可以同时响应多个客户端
• 服务端每接受一个客户端,就启动一个独立的线程与之对 应
• 客户端或者服务端都可以选择关闭这对Socket的通道
• 实例 –服务端先启动,且一直保留
–客户端后启动,可以先退
Server:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpServer {
public static void main(String[] args) {
try {
ServerSocket ss=new ServerSocket(8888);//驻守在8888端口;
Socket s=ss.accept();//阻塞,等待客户端的接入;
System.out.println("有客户端接入:");
InputStream ios=s.getInputStream();
DataInputStream iop=new DataInputStream(ios);//包装输入流;
OutputStream dos=s.getOutputStream();
DataOutputStream dop=new DataOutputStream(dos);//包装输出流;
Scanner sc=new Scanner(System.in);
while(true)
{
String str=sc.next();
if(str.equalsIgnoreCase("quit"))
{
break;
}
else
{
System.out.println("向客户端发出:"+str);
dop.writeUTF(str+ System.getProperty("line.separator"));
String dr=iop.readUTF();//读入客户端发来的消息;
System.out.println("收到客户端消息:"+dr);
}
}
ss.close();
s.close();
ios.close();
dos.close();
sc.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
Client:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) {
try {
Socket s=new Socket(InetAddress.getByName("127.0.0.1"), 8888);
InputStream ss=s.getInputStream();
DataInputStream ios=new DataInputStream(ss);
OutputStream dop =s.getOutputStream();
DataOutputStream dos=new DataOutputStream(dop);
Scanner sc=new Scanner(System.in);
while(true)
{
String str=sc.next();
if(str.equalsIgnoreCase("quit"))
{
break;
}
else
{
System.out.println("向客户端发出:"+str);
dos.writeUTF(str+ System.getProperty("line.separator"));
String dr=ios.readUTF();
System.out.println("收到服务端消息:"+dr);
}
}
s.close();
ss.close();
dop.close();
sc.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以上的例子,服务端只能连接一个客户端,所以要想同时连接多个客户端,则需要用到线程类,在服务端里每循环一次,就NEW一个线程类对象,让它去与客户端连接,
import java.net.*;
public class TcpServer2
{
public static void main(String [] args)
{
try
{
ServerSocket ss=new ServerSocket(8001);
while(true)
{
Socket s=ss.accept();
System.out.println("来了一个client");
new Thread(new Worker(s)).start();
}
//ss.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
线程类:
import java.net.*;
import java.io.*;
class Worker implements Runnable {
Socket s;
public Worker(Socket s) {
this.s = s;
}
public void run() {
try {
System.out.println("服务人员已经启动");
InputStream ips = s.getInputStream();
OutputStream ops = s.getOutputStream();
DataInputStream br=new DataInputStream(ips);
//BufferedReader br = new BufferedReader(new InputStreamReader(ips));
DataOutputStream dos = new DataOutputStream(ops);
while (true) {
String strWord = br.readUTF();
System.out.println("client said:" + strWord +":" + strWord.length());
if (strWord.equalsIgnoreCase("quit"))
break;
String strEcho = strWord + " 垃圾";
// dos.writeBytes(strWord +"---->"+ strEcho +"\r\n");
System.out.println("server said:" + strWord + "---->" + strEcho);
dos.writeUTF(strWord + "---->" + strEcho + System.getProperty("line.separator"));
}
br.close();
// 关闭包装类,会自动关闭包装类中所包装的底层类。所以不用调用ips.close()
dos.close();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上的例子都是客户端输入一句,才能看见服务端的消息,同样,服务端要想看到消息也得先输入一句,这就造成交流不同步,
要使服务端和客户端能同时收发信息,需要将接收信息和发送信息放在不同的线程中,这样可以同时
- SendThread 发送消息线程
- RecieveThread 接受消息线程
- Server一旦接受到连接,就启动收发两个线程
- Client 一旦建立了连接,就启动收发两个线程
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Scanner;
public class RecieveThread extends Thread{
private Socket s;
public RecieveThread(Socket s)
{
this.s=s;
}
public void run() {
InputStream ios;
try {
ios = s.getInputStream();
DataInputStream ss=new DataInputStream(ios);
while(true)
{
String str=ss.readUTF();
System.out.println(str);}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class SendThread extends Thread{
private Socket s;
public SendThread(Socket s)
{
this.s=s;
}
public void run() {
try
{
OutputStream dop=s.getOutputStream();
DataOutputStream dos=new DataOutputStream(dop);
while(true)
{
Scanner sc=new Scanner(System.in);
String str=sc.next();
dos.writeUTF(str);
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
public class TcpClient {
public static void main(String[] args) {
try {
Socket s=new Socket(InetAddress.getByName("192.168.1.10"), 8002);
new SendThread(s).start();
new RecieveThread(s).start();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class TcpServer {
public static void main(String[] args) {
try {
ServerSocket ss=new ServerSocket(8002);
Socket s=ss.accept();//阻塞,等待客户端接入;
System.out.println("客户端接入:");
new SendThread(s).start();
new RecieveThread(s).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}