工作中三角形法则 1.技术,2.管理(管理自己的时间)3.沟通
基础内容
1.网络基础
2.TCP/IP协议
3.IP地址
4.Socket通信(TCP/UDP)
网络的基础概念
网络通信协议
网络通信分层:
分层模型:
数据在网络之间的传输要实现数据的封装和拆分
ip提供了一个巨大的贡献:ip给每台机器一个独一无二的地址(四个字节来代表一个ip,所以最大的ip不会超过255) IPV4 ip地址:网络段+主机号 a类网,第一个字段是固定的,例如192.是固定的,后面的3个位数都是不固定的,所有有256*256*256,B类网,第一个字段和第二个字段是固定的,例如192.168是固定的,后面两位是可选的,256*256,C类网,第一个字段和第二,第三个字段都固定192.168.10,所有只有256个网址可以用 。子网掩码中凡是为1的都是网络id,凡是为0 的都是主机id,子网掩码可以分内网,网关一般是连两处的 PS:若想了解网络的底层,可以看《TCP/IP详解》
两种机器通话方式
1.TCP(可靠的传输机制),三层握手机制 特点1:建立一个虚拟链接 2:默认传输会传输到 3:传输分前后,后一句不会比前一句先到(网络转账)。必须有回应的
2.UDP(不可靠的传输机制)(网络视频),可以丢包 ,直接说一句,不管是否有回应
java的socet(插座) TCP中的client端是socket。TCP的customer端是ServerSocket,端口号是用来区分同一台机器上的不同的应用程序,一台机器最多可以有65536个应用程序
若自己的程序要定义端口号最好用1024以上的端口,1024以下的端口可能被系统占用,端口号分为Tcp端口和UDP端口,各个端口可以跑65536个程序,其中TCP端口8888和UDP端口8888是不同的
端口占用的错误:两个程序占用同一个端口
TCP通信模型:
sever程序
//运行时应该先启动server,然后再启动client,,记住,server和client是配套使用的
import java.net.*;
import java.io.*;
public class TcpServer
{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(6666);//不间断的执行,在等待server的链接,通过6666端口来新建
while(true){
Socket s = ss.accept();//接受与否由server端来决定,若没有客户端连接,则会一直等待
DataInputStream dis = new DataInputStream(s.getInputStream());//输入管
System.out.println(dis.readUTF());//readUTF()是阻塞式的,除非对方写了东西过来才会有回应,accept()方法也是阻塞式的
dis.close();
s.close();
}
}
}
client程序
//运行时应该先启动server,然后再启动client,,记住,server和client是配套使用的
import java.net.*;
import java.io.*;
public class TcpServer
{
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(6666);//不间断的执行,在等待server的链接,通过6666端口来新建
while(true){
Socket s = ss.accept();//接受与否由server端来决定,若没有客户端连接,则会一直等待
DataInputStream dis = new DataInputStream(s.getInputStream());//输入管
System.out.println(dis.readUTF());//readUTF()是阻塞式的,除非对方写了东西过来才会有回应,accept()方法也是阻塞式的
dis.close();
s.close();
}
}
}
一端读,一端写
/*简单的client/server程序
源文件名称:TestServer.java/TestClient.java
要点:
1.java socket编程步骤
2.Socket/ServerSocket类用法
3.通过Socket对象可以获取通信对方Socket的信息
*/
import java.net.*;
import java.io.*;
public class TestServer
{
public static void main(String[] args){
try
{
ServerSocket ss = new ServerSocket(8888);
while(true){
Socket s = ss.accept();//等待客户端通信
OutputStream os = s.getOutputStream();//建立输出管道
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("客户端的端口号是:"+s.getPort()+",客户端的ip地址是:"+s.getInetAddress());
dos.flush();
dos.close();
s.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/*简单的client/server程序
源文件名称:TestServer.java/TestClient.java
要点:
1.java socket编程步骤
2.Socket/ServerSocket类用法
3.通过Socket对象可以获取通信对方Socket的信息
*/
import java.net.*;
import java.io.*;
public class TestClient
{
public static void main(String[] args){
try
{
Socket s = new Socket("127.0.0.1",8888);
DataInputStream dis = new DataInputStream(s.getInputStream());
System.out.println(dis.readUTF());
dis.close();
s.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
一端又读,又写
import java.net.*;
import java.io.*;
public class TestSocketServer
{
public static void main(String[] args){
OutputStream os = null;
InputStream is = null;
try
{
ServerSocket ss = new ServerSocket(5888);//设置接听端口
Socket s = ss.accept();
os = s.getOutputStream();
is = s.getInputStream();
DataOutputStream dos = new DataOutputStream(os);//发消息到客户端(写出)
DataInputStream dis = new DataInputStream(is);//接收客户端的消息(读入)
String s1 = dis.readUTF();
//server端先从client读一个数据,然后在写数据到client端口
if(null!=s){
System.out.println(s1);
System.out.println("客户端端口号:"+s.getPort());
System.out.println("客户端的地址是:"+s.getInetAddress());
}
//发消息到客户端
dos.writeUTF("hi, client");
dis.close();
dos.close();
s.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
客户端也是又读又写:
import java.net.*;
import java.io.*;
public class TestSocketClient
{
public static void main(String[] args){
OutputStream os = null;
InputStream is = null;
try
{
Socket s = new Socket("127.0.0.1",5888);//建立连接
os = s.getOutputStream();
is = s.getInputStream();
DataOutputStream dos = new DataOutputStream(os);
DataInputStream dis = new DataInputStream(is);
//由于在server端是先读后写,所以在client端必须要先写后读,如果两个都是先读后写的话,那两个程序都会在哪里傻傻等待
dos.writeUTF("hi server");
String s1 = dis.readUTF();
if(s1!=null){
System.out.println(s1);
dos.close();
dis.close();
//socket一定要记得关闭,如果不关闭,就会出现这样的问题 java.net.SocketException: Connection reset或者是java.io.EOFException错误
s.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
开通两个端口之后运行的结果如下图
聊天模式,客户端说一句,服务器端必须要回应一句,,这个运行结果很有趣,自己还不是太懂里面的知识,多看两遍
import java.net.*;
import java.io.*;
public class TalkServer
{
public static void main(String[] args){
try
{
ServerSocket ss = new ServerSocket(4700);
Socket s = ss.accept();//等待客户端的连接
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));//建立从客户端读消息
PrintWriter pw = new PrintWriter(s.getOutputStream());//输出管道,写消息到客户端
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));//从键盘中读消息
//server是先读后写,所以对应到client端是先写后读 这里的是先从客户端读一行,然后显示出来,然后从自己的命令行读一行,然后写到client端
System.out.println("client:"+br.readLine());//从客户端读一行
String line = sin.readLine();
while(!line.equals("bye")){
//若没有从键盘中输入bye的时候
pw.println(line);//将line写到客户端。
pw.flush();
System.out.println("Server:"+line);
System.out.println("Client:"+br.readLine());//从客户端中再读一行
line = sin.readLine();//从键盘中再读一行
}
br.close();
pw.close();
sin.close();
s.close();
ss.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
client端
import java.net.*;
import java.io.*;
public class TalkClient
{
public static void main(String[] args){
try
{
Socket s = new Socket("127.0.0.1",4700);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(s.getOutputStream());
BufferedReader bis = new BufferedReader(new InputStreamReader(s.getInputStream()));
String readLine = null;
readLine = br.readLine();
while(!readLine.equals("bye")){
pw.println(readLine);
pw.flush();
System.out.println("client:"+readLine);
System.out.println("SERVER:"+bis.readLine());
readLine = br.readLine();
}
br.close();
pw.close();
bis.close();
s.close();
}
catch (Exception e )
{
e.printStackTrace();
}
}
}
UDP:效率高,不可靠,(下面的程序是将一个字符串在客户端和服务器端进行传输)
import java.net.*;
public class TestUDPServer
{
public static void main(String[] args) throws Exception{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);//新建了一个包裹对象,
//这个包裹才是用来接收对方UDP发过来的东西,但是在包裹里面实际上是buf接收,且数据存在buf中。具体占所有的buf
DatagramSocket ds = new DatagramSocket(5678);
while(true){
ds.receive(dp);//等对方发数据。只要有人发数据。socket就会将包袱仍在dp中
System.out.println(new String(buf,0,dp.getLength()));///包袱中实际收了多少数据,string构造方法通过某一个字节数组的一部分构建成为一个字符串,然后打印出来
}
}
}
import java.net.*;
public class TestUDPClient
{
public static void main(String[] args){
try
{
byte[] buf = (new String("hello")).getBytes();//将一个字符串解析成一个字节数组
DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",5678));//将字节数组中的所有的内容都发送出去。UDP本身是没有连接,写地址的原因是对于每一个UDP包都要写地址
//,才能知道要将该包发送到哪里去
DatagramSocket ds = new DatagramSocket(9999);//client端口占据9999端口,用这个端口向server端口为5678的发送包裹
ds.send(dp);
ds.close();
}
catch (Exception e)
{
}
}
}
在服务器端和客户端传输一个long类型的值
import java.net.*;
import java.io.*;
public class TestUDPClient
{
public static void main(String[] args){
try
{
//将一个long类型的数发送到服务端
long n = 10000L;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//将long类型的数写到bos中
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(n);
byte[] buf = bos.toByteArray();
DatagramPacket dp = new DatagramPacket(buf,buf.length,new InetSocketAddress("127.0.0.1",5678));//将字节数组中的所有的内容都发送出去。UDP本身是没有连接,写地址的原因是对于每一个UDP包都要写地址
//,才能知道要将该包发送到哪里去
DatagramSocket ds = new DatagramSocket(9999);//client端口占据9999端口,用这个端口向server端口为5678的发送包裹
ds.send(dp);
ds.close();
}
catch (Exception e)
{
}
}
}
import java.net.*;
import java.io.*;
public class TestUDPServer
{
public static void main(String[] args) throws Exception{
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);//新建了一个包裹对象,
//这个包裹才是用来接收对方UDP发过来的东西,但是在包裹里面实际上是buf接收,且数据存在buf中。具体占所有的buf
DatagramSocket ds = new DatagramSocket(5678);
while(true){
ds.receive(dp);//等对方发数据。只要有人发数据。socket就会将包袱仍在dp中
//接收传过来的byte[]然后转为long类型
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
DataInputStream dis = new DataInputStream(bais);
System.out.println(dis.read());///包袱中实际收了多少数据,string构造方法通过某一个字节数组的一部分构建成为一个字符串,然后打印出来
}
}
}