2017年7月3日 上午8:00
TCP:传输控制协议
UDP:数据报文协议
端口 :16位
三类
- 公认端口:0~1023
- 注册端口:1024-49151
- 动态和、私有端口:49151~65535
常用端口:
Telent:23
Stmp:25
Ftp:21
Http:80
常用对象:
ServerSocket
- ServerSocket(port):创想serverSocket实例
- accept()等待客户端连接
- Public InetAddress getInetAddress()返回服务器的Ip地址
- Public boolean isCloseed();赶回ServerSocket的关闭状态
- Public void close();关闭ServerSockets
Socket
- Socket(String host,int port):构造socket对象,同时,指定要连接服务器的主机名和端口号
- public inputStream getInputStream:返回套接字的输入流
- pubilc OutputStream .getOutputStream()返回套接字的输入流
- Public boolean isClosed()判断套接字是否关闭
- Public void close():关闭socket
InetAddress
- public static InetAddress(String host):通过主机名或IP地址得到一个InetAddress对象
- String getHostName();获取ip地址对应的主机名
- String getHostAddress();返回ip地址字符串
注:他们处理的都是字节流
使用PrintWriter的例程
网络编程的服务端步骤比较单一:
1. ServerSocket对象
2. 创建Socket对象
3. inputStream对象
4. BufferedReader对象
5. outputStream对象
6. printWriter对象
7. 读
8. 写
注:他们都是一条流水线,前一个对象产生下一个对象
例程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;
public class Server1 {
public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(7799);
Socket socket= ss.accept(); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); PrintWriter pw= new PrintWriter(socket.getOutputStream()); String content = br.readLine(); if(content != null){ System.out.println("获取到的数据是:"+content); } pw.write("服务端收到数据"); pw.close(); br.close(); is.close(); socket.close(); ss.close(); }
}
|
网络编程的客户端步骤比较单一:
1. 创建Socket对象
2. outputStream对象
3. printWriter对象
4. inputStream对象
5. BufferedReader对象
6. 写
7. 读
例程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1",7799); OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); pw.write("我要访问服务端"); pw.flush(); socket.shutdownOutput(); String result = br.readLine(); if(result != null){ System.out.println("获取到的数据是:"+result); } br.close(); socket.close(); }
}
|
注:
- 他们都是一条流水线,前一个对象产生下一个对象
- 客户端和服务的不能同时创建输入流
- 这里socket.shutdownOutput的作用
- 【TCP】s.shutdownOutput();这行代码的牛逼之处 - 闲着没事_玩玩JAVA的专栏 - 博客频道 - CSDN.NET
- 第一种方法close流,相当于给流中加入一个结束标记-1
- 第二种方法:s.shutdownOutput();关闭客户端的输出流。相当于给流中加入一个结束标记-1.
- 就像字符串的结尾一样
- 服务端没写socket.shutdownOutput,用pw.close代替了
错误:没有打开服务端就开启客户端

扩展:
以上代码使用
DateOutputStream 和 DateInputStream也可以
使用对象流的例程:
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package package1;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1",7799); Pet pet = new Pet("狗",1); OutputStream os = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); oos.writeObject(pet); oos.flush(); String string = br.readLine(); if(string != null){ System.out.println("接收到的信息是:"+string); } br.close(); is.close(); oos.close(); os.close(); socket.close(); }
}
|
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package package1;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1",7799); Pet pet = new Pet("狗",1); OutputStream os = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); oos.writeObject(pet); oos.flush(); String string = br.readLine(); if(string != null){ System.out.println("接收到的信息是:"+string); } br.close(); is.close(); oos.close(); os.close(); socket.close(); } }
|
Pet类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package package1;
import java.io.Serializable;
public class Pet implements Serializable{ private String name; private int id;
public Pet(String name, int id) { super(); this.name = name; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
|
错误:Pet类没有序列号接口: implements Serializable

服务器常开例程(死循环方式)
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package package2;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",7799); Pet pet = new Pet("狗","狗","男"); OutputStream os = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); oos.writeObject(pet); oos.flush(); String string = br.readLine(); if(string != null){ System.out.println("接收到的信息是:"+string); } br.close(); is.close(); oos.close(); os.close(); socket.close(); } }
|
pet类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package package2;
import java.io.Serializable;
public class Pet implements Serializable{
private static final long serialVersionUID = 1L; private String name; private String type; private String sex; public Pet(String name, String type, String sex) { super(); this.name = name; this.type = type; this.sex = sex; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
|
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package package2;
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException, ClassNotFoundException { while(true){ ServerSocket ss = new ServerSocket(7799); Socket socket = ss.accept(); InputStream is = socket.getInputStream(); ObjectInputStream br = new ObjectInputStream(is); OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); Pet pet = (Pet) br.readObject(); if(pet != null){ System.out.println("name : "+pet.getName()+"id :"+pet.getSex()); FileWriter fw = new FileWriter("hello_pet.txt"); BufferedWriter bw = new BufferedWriter(fw); bw.write("name : "+pet.getName()+"id :"+pet.getSex()); bw.flush(); bw.close(); } pw.write("客户端已得到pet对象"); pw.close(); os.close(); br.close(); is.close(); socket.close(); ss.close(); } }
}
|
注:
1. 通过换host可以实现局域网下访问,要有以下两个条件
1. 但是需要有相同的序列号这里使用的是IL
2. Pet所在的包要相同
服务器常开例程2(死循环方式+Thread)
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket;
public class PetServer { public static void main(String[] args) { try { ServerSocket serverSocket=new ServerSocket(8800); Socket socket=null; int num=0; while(true){ socket=serverSocket.accept(); ServerThread serverThread=new ServerThread(socket); serverThread.start(); num++; System.out.println("有"+num+"只宠物在本店注册!\n"); InetAddress ia=socket.getInetAddress(); String ip=ia.getHostAddress(); System.out.println("本宠物主人的IP地址为:"+ip); String name=ia.getHostName(); System.out.println("本宠物主人的主机名为:"+name); } } catch (IOException e) { e.printStackTrace(); } } }
|
Thread类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket;
public class ServerThread extends Thread { Socket socket=null; public ServerThread(Socket socket){ this.socket=socket; } public void run(){ try { InputStream is=socket.getInputStream(); ObjectInputStream ois=new ObjectInputStream(is); OutputStream os=socket.getOutputStream(); PrintWriter pw=new PrintWriter(os); BufferedWriter writer = new BufferedWriter(new FileWriter(new File("pet.txt"), true)); Pet pet=(Pet)ois.readObject(); writer.write("----宠物注册信息----"); writer.write("姓名:"+pet.getName()); writer.write("品种:"+pet.getType()); writer.write("性别:"+pet.getGender()); writer.flush(); String reply="恭喜,您的宠物已经在本店注册成功!"; pw.write(reply); pw.flush(); pw.close(); os.close(); ois.close(); is.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
|
比较两种服务器常开的:
1. 第一种的思路是:
1. 服务器整体写一个循环,这个循环中包含全部的内容,ServerSocket对象和以及想的close()
2. 这个种方法操作流程是:一个客户端访问完,这个循环走到accept()方法处,等待下一次客户端的访问(server就是一个苦力,真可怜个)。
2. 第二种的思路是:
1. 首先是写一个循环,循环的作用是让服务器不停止运行,然后,写一个Thread类
2. 这个类的入口是:accpet()方法产生的socket对象
3. 执行的内容是:获取客户端内容,然后给一个回馈
4. Thread类写完之后,最后在while()循环中开启Thread的一个线程,并计数
5. 这种方法执行的流程是:整个过程可以看成是一个生活场景。Server.class就像一个前台人员,她的主要任务有两个:一个是迎接来宾(client.class的访问),一个是命令他的小弟Thread的对象去完成当前用户的要求,然后她接着笑脸迎接下一个用户(boss就是boss,美女会笑就行,她其实也没干啥)

3. 区别:
1. 在每次一个client访问模式下,这两种是没有区别的
2. 但是,当多个client并行访问时,第一种是无法实现的,因为所有的任务都是他一个人来执行,干完一个才能干下一个。第二种是可以实现的,在这种情况下有一个团伙,美女boss管理者一堆小弟
两种客户端和服务端交互方式,其实都行,不过习惯使用第二种:
第一种:BufferedWriter
1 2 3 4 5 6
| OutputStream is2 = socket.getOutputStream(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(is2));
bw.write("name : "+pet.getName()+"id :"+pet.getSex()); bw.flush(); bw.close();
|
第二种:使用PrintWriter
1 2 3 4 5
| OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os);
pw.write("客户端已得到pet对象"); pw.close();
|
注:细节中应该还是有区别的,没有仔细的测试!