之前学网络编程这块,就是感觉云里雾里,就想对老师说一句:你说啥呢?这两天学框架,遇到个bug怎么也是解决不了了;这两天还赶上元旦,老师们都放假;进行不下去就回来复习复习吧!看看最头疼的网络编程;重新在看一遍,还真有种知新而温故的感觉!废话不多说,我们看代码;
在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。
Socket 类:发送 TCP 消息。
ServerSocket 类:创建服务器。
代码如下:
服务端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器类
* */
public class ServerTest {
public static void main(String[] args) throws IOException {
// 创建serverSocket对象,并指定端口;
ServerSocket ss = new ServerSocket(9999);
// 利用accept()方法,进行监听 返回一个Socket对象
Socket client = ss.accept();
// 接收数据(获取输入流)由于接收到是字节(也就是数字)需要转换成字符read:从输入流读取数据的下一个字节。
InputStream is = client.getInputStream();
System.out.println((char)is.read());
// 发出响应(获取输出流)write():将 b.length字节从指定的字节数组写入此输出流。
OutputStream os = client.getOutputStream();
os.write("收到".getBytes());
// 关闭流
if(os!=null) {
os.close();
}
if(is!=null) {
is.close();
}
if(client!=null) {
client.close();
}
}
}
客户端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户类
* */
public class ClientTest {
public static void main(String[] args) throws IOException {
// 创建Socket对象
Socket socket = new Socket("192.168.10.102",9999);
// 输出数据
OutputStream os = socket.getOutputStream();
// write()中的参数只能是,字符类型的
os.write('a');
// 接收响应
InputStream is = socket.getInputStream();
byte[] b = new byte[1024];//中转站,存储读到的数据
int len = 0;//读到的个数,当个数为-1时,证明没有数据;
if((len=is.read(b))!=-1) {
// 利用String的构造方法,将读到的数据输出到控制台
System.out.println(new String(b,0,len));
}
// 关闭流
if(is!=null) {
is.close();
}
if(os!=null) {
os.close();
}
if(socket!=null) {
socket.close();
}
}
}
输出效果
代码如下:
服务端
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务器类
* */
public class ServerTest2 {
public static void main(String[] args) throws IOException {
// 创建serverSocket对象,并指定端口;
ServerSocket ss = new ServerSocket(9999);
// 利用accept()方法,进行监听 返回一个Socket对象
Socket client = ss.accept();
// 接收数据 获取数据输入流 数据流的参数需要一个字节流
DataInputStream dis = new DataInputStream(client.getInputStream());
System.out.println(dis.readUTF());
// 发出响应(获取数据输出流)
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("收到");
// 关闭流
if(dos!=null) {
dos.close();
}
if(dis!=null) {
dis.close();
}
if(client!=null) {
client.close();
}
if(ss!=null) {
ss.close();
}
}
}
客户端
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
/**
* 客户类
* */
public class ClientTest2 {
public static void main(String[] args) throws IOException {
// 创建Socket对象
Socket socket = new Socket("192.168.10.102",9999);
// 输出数据 使用数据流进行数据的传输 参数需要一个字节流
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
// writeUTF()是写入的方法;
dos.writeUTF("hello world");
// 接收响应
DataInputStream dis = new DataInputStream(socket.getInputStream());
// readUTF()是读取数据的方法
System.out.println(dis.readUTF());
// 关闭流
if(dis!=null) {
dis.close();
}
if(dos!=null) {
dos.close();
}
if(socket!=null) {
socket.close();
}
}
}
运行效果
创建两个项目(服务器项目、客户端项目)
服务器项目
User类
import java.io.Serializable;
public class User implements Serializable{
// 必须要继承Serializable接口 , 否则不能被序列化
//为了防止读写的序列化id不同,一定要指定一个固定的序列id 最好不要选择默认的id
private static final long serialVersionUID = 8251855228567334134L;
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public User(String name, String password) {
super();
this.name = name;
this.password = password;
}
public User() {
super();
}
}
服务器类
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import com.bjsxt.thread.ServerThread;
/**
* 服务器类
* */
public class Server {
public static void main(String[] args) throws IOException, ClassNotFoundException{
// 常见ServerSocket对象; 并指定端口号
ServerSocket ss = new ServerSocket(10000);
// 监听客户端 accept()方法进行监听 并返回一个Socket对象
// 需要使用循环来监听,不能只监听一次
while(true) {
Socket client = ss.accept();
// 创建线程对象
ServerThread st = new ServerThread(client);
// 开启线程
new Thread(st).start();
}
}
}
添加线程类ServerThread
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import com.bjsxt.pojo.User;
/**
* 将获取每一个客户端都要执行的代码,封装到该类中,并实现Runnable接口,完成多线程
* */
public class ServerThread implements Runnable{
private Socket client;
public ServerThread(Socket client) {
super();
this.client = client;
}
// 线程中的异常必须处理掉,不能抛出;
@Override
public void run() {
// 想要看到谁在请求登录必须要在线程类的方法中添加 ,如果在服务其中添加会出现main请求登录的字样
System.out.println(Thread.currentThread().getName()+"正在请求登录");
// 获取对象输入流 需要一个字节流
ObjectInputStream ois = null;
// 获取数据输出流 响应是字符串 所以用数据输出流 参数需要一个字节流
DataOutputStream dos = null;
try {
ois = new ObjectInputStream(client.getInputStream());
// 获取信息 返回一个object对象,将其转换为user对象
User user = (User)ois.readObject();
// 通过getInetAddress()方法获取InetAddress对象,并获取客户端信息;
System.out.println(client.getInetAddress().getHostAddress()+"请求登录"+"\t用户名:"+user.getName()+"\t密码:"+user.getPassword());
dos = new DataOutputStream(client.getOutputStream());
// 产生响应 判断用户名与密码是否正确
String str = null;
if("miwa".equals(user.getName())&&"miwa".equals(user.getPassword())) {
str = "登录成功";
}else {
str = "用户名或密码错误";
}
dos.writeUTF(str);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 关闭流 倒着关
if(dos!=null) {
try {
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(ois!=null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(client!=null) {
try {
client.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
客户端项目
User类
import java.io.Serializable;
public class User implements Serializable{
// 必须要继承Serializable接口 , 否则不能被序列化
//为了防止读写的序列化id不同,一定要指定一个固定的序列id 最好不要选择默认的id
private static final long serialVersionUID = 8251855228567334134L;
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public User(String name, String password) {
super();
this.name = name;
this.password = password;
}
public User() {
super();
}
}
客户端类
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import com.bjsxt.pojo.User;
/**
* 客户端
* */
public class Client {
public static void main(String[] args) throws IOException {
// 获取Socket对象 并给定服务器地址,以及端口号
Socket socket = new Socket("192.168.10.102",10000);
// 获取 对象输出流 为了实现登录 ,需要将登录信息封装成对象 参数需要一个字节流对象
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
// 创建用户对象
User user = getUser();
// 发送信息
oos.writeObject(user);
// 接收响应 响应是字符串类型,所以用数据流接收 参数需要一个字节流
DataInputStream dis = new DataInputStream(socket.getInputStream());
// 将响应输出到控制台 readUTF()方法直接返回一个String类型,可以直接输出;
System.out.println(dis.readUTF());
// 关闭流
if(dis!=null) {
dis.close();
}
if(oos!=null) {
oos.close();
}
if(socket!=null) {
socket.close();
}
}
public static User getUser() {
// 获取键盘输入对象
Scanner s = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = s.next();
System.out.println("请输入密码:");
String password = s.next();
return new User(username,password);
}
}
运行效果