之前因为学校的java课程设计做了一个很简单的聊天室,现在想起来真的想吐。
网络编程之socket编程是挺简单的,但是底层的东西总是不能理解,后来我才知道,一直使用java使我变得不关心底层,总是期待某些类的某些方法在API文档上。于是乎,底层关我屁事,我只需要做出来就行了,这玩意就是这个样子的。
感觉这玩意很神奇,你看那个YY直播和斗鱼TV,那些肯定是靠流来实现的。 类似于QQ,你看这玩意可以聊天,虽然是基于socket和多线程,但是我还是觉得,QQ内部规定的协议规定得多少啊。 还是别想了,就好像原始人在构思机器人一样。 水平不够。。。。
一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。
答案就是:由IP地址可以唯一地确定Internet上的一台主机。
而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。
UDP: 1 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
2 UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
3 UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方
TCP: 1 面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中需要连接时间。
2 TCP传输数据大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大的数据。
3 TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。
了解到这里已经够了。马上上代码
/**
* 客户端代码
* @author suibian
*
*/
public class Client {
public static void main(String[] args) throws Exception {
Socket s=new Socket("localhost",10000); //创建一个socket对象
Scanner sc=new Scanner(System.in);
InputStreamReader isr=new InputStreamReader(s.getInputStream()); //获取输入流
BufferedReader br=new BufferedReader(isr); //当然有其他的方式
OutputStream oos=s.getOutputStream(); //获取输出流
PrintWriter out=new PrintWriter(oos);
System.out.println("Write to Server :");
String words=sc.nextLine();
while(!words.equals("bye")){ //如果输入不是bye的话,那么发送到服务器中去
out.println(words);
out.flush(); //一定要记得刷新一下流,否则服务器收不到数据
String response=br.readLine(); //获取服务器返回的数据
System.out.println("Server response:"+response);
words=sc.nextLine();
}
s.close(); //最后记得要关闭
}
}
/**
* 服务器端代码
* @author suibian
*
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket socket=new ServerSocket(10000); //监听本机端口为10000
System.out.println("Server start! "+socket.getInetAddress());
Scanner sc=new Scanner(System.in);
while(true){
Socket s=socket.accept();
System.out.println("One client connectioned");
NetClient client=new NetClient(s); //放到一个线程中去处理好
new Thread(client).start();
}
}
static class NetClient implements Runnable{
private Socket s;
/*是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了或者你flush的时候,再读入内存,就是为了提供读的效率而设计的。*/
private BufferedReader reader;
/*PrintWriter是 打印流是向文件输 的首选的类 ,不用关注他输入的是不是中文 ,这个类已经给我们处理好了,不会出现中文乱码*/
private PrintWriter out;
private Scanner scanner=new Scanner(System.in);
public NetClient(Socket s) throws IOException {
this.s = s;
InputStreamReader isr=new InputStreamReader(s.getInputStream());
reader=new BufferedReader(isr);
OutputStream oos=s.getOutputStream();
out=new PrintWriter(oos);
}
public void run() {
try {
String clientWords = reader.readLine(); //从客户端读到的数据
System.out.println("Clent:"+s.getRemoteSocketAddress()+" to server:"+clientWords);
System.out.println("Write what u want to say?");
String response=scanner.nextLine(); //服务器返回给客户端的数据
while(!response.equals("bye")){
out.println(response);
out.flush();
clientWords=reader.readLine();
System.out.println("Clent:"+s.getRemoteSocketAddress()+"to server:"+clientWords);
if(clientWords.equals("bye")){
System.out.println("Clent "+s.getRemoteSocketAddress()+" disconnection");
break;
}
System.out.println("Write what u want to say?");
response=scanner.nextLine();
}
out.close();
reader.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
再来一个类似于ATM的网络协议编程
需求:设计一个简单的银行访问协议,如下 : 客户机请求 服务齐全响应 意义 BALANCE n n 余额 客户机将获得账户n的余额 DEPOSIT n a n 余额 将数量为a的款项存入账户n WITHDRAW n a n 余额 从账户支出数量为a的款项 QUIT 无响应 退出连接 |
public class Account {
private double balance;
public Account(){
balance=0;
}
public Account(double initialBalance){
balance=initialBalance;
}
/**
* 返回账户余额
*/
public double getBalance() {
return balance;
}
/**
*存钱
*/
public void deposit(double amount){
balance+=amount;
}
/**
* 取钱
*/
public void withdraw(double amount){
balance-=amount;
}
}
/**
* 银行类
* @author suibian
*
*/
public class Bank {
private List<Account> accounts;
public Bank(int initalSize){
accounts=new ArrayList<Account>();
for(int i=0;i<initalSize;i++){
accounts.add(new Account());
}
}
/**
* 存钱的业务
*/
public void deposit(int accountId,double amount){
accounts.get(accountId-1).deposit(amount);
}
/**
* 取钱业务
*/
public void withdraw(int accountId,double amount){
accounts.get(accountId-1).withdraw(amount);
}
/**
* 获取余额
*/
public double getBalance(int accountId){
return accounts.get(accountId-1).getBalance();
}
}
/**
* 客户端代码
* @author suibian
*
*/
public class ATMClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket=new Socket("localhost",8888);
InputStream stream=socket.getInputStream();
OutputStream output=socket.getOutputStream();
System.out.println("Connected Server"+socket.toString());
Scanner in=new Scanner(stream);
PrintWriter out=new PrintWriter(output);
/*客户机将获得账户n的余额 */
String command="BALANCE 3\n";
out.print(command);
out.flush();
String response=in.nextLine();
System.out.println("result is:"+response);
System.out.println("================================================");
/*将数量为a的款项存入账户n*/
command="DEPOSIT 3 1000\n";
System.out.println("Client send request:"+command);
out.print(command);
out.flush();
response=in.nextLine();
System.out.println("result is:"+response);
System.out.println("================================================");
/*从账户支出数量为a的款项*/
command="WITHDRAW 3 500\n";
System.out.println("Client send request:"+command);
out.print(command);
out.flush();
response=in.nextLine();
System.out.println("result is:"+response);
System.out.println("================================================");
/*退出连接*/
command="QUIT\n";
System.out.println("Client send request:"+command);
out.print(command);
out.flush();
response=in.nextLine();
System.out.println("result is:"+response);
System.out.println("================================================");
}
}
/**
* 服务端代码
* @author suibian
*
*/
public class ATMServer {
public static void main(String[] args) throws IOException {
ServerSocket socket=new ServerSocket(8888);
Bank bank=new Bank(10); /*开启10个人的小银行*/
System.out.println("Server start");
while(true){
Socket s=socket.accept();
System.out.println("user join,start thread"+s.toString());
/*将对象传进去,然后交给线程处理*/
new Thread(new ServerThread(s,bank)).start();
}
}
}
public class ServerThread implements Runnable {
private Socket s;
private Bank bank;
Scanner in;
PrintWriter out;
public ServerThread(Socket s,Bank bank){
this.s=s;
this.bank=bank;
}
public void run() {
try {
InputStream instream=s.getInputStream();
in =new Scanner(instream);
OutputStream stream=s.getOutputStream();
out=new PrintWriter(stream);
while(true){ //死循环
String response=in.next(); /*以换行或者空格符为分界线接受下一个String类型变量*/
System.out.println("Server received command: "+response);
if(response.equals("QUIT")||!in.hasNext()){
break;
}
deal(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void deal(String response){
int accountId=in.nextInt();
if(response.equals("DEPOSIT")){
double amount=in.nextDouble(); //这个有意思
bank.deposit(accountId, amount);
}else if(response.equals("WITHDRAW")){
double amount=in.nextDouble();
bank.withdraw(accountId, amount);
}else if( !response.equals("BALANCE") ){
out.print("错误命令");
out.flush();
return;
}
out.println(accountId+" "+bank.getBalance(accountId)); /*返回成功语句给客户端 REBALANCE 3 1500*/
out.flush();
}
}
这些个东西很简单吧。