Socket编程

之前因为学校的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 余额 从账户支出数量为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();
	}
}



这些个东西很简单吧。 




你可能感兴趣的:(thread,socket)