【Java】关于网络编程的那些事

网络基础知识

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();
		}
	}
}

以上的例子都是客户端输入一句,才能看见服务端的消息,同样,服务端要想看到消息也得先输入一句,这就造成交流不同步,
要使服务端和客户端能同时收发信息,需要将接收信息和发送信息放在不同的线程中,这样可以同时

  1. SendThread 发送消息线程
  2. RecieveThread 接受消息线程
  3. Server一旦接受到连接,就启动收发两个线程
  4. 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();
		}

	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术的小小林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值