`
feng1990liu
  • 浏览: 8302 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
文章分类
社区版块
存档分类
最新评论

通信小结

 
阅读更多

     最近好多天都在写通信的程序,刚开始讲时,服务器和客户端都没用到自己设计的界面,觉得很简单,服务器端有一个ServerSocket,客户端有一个Socket,简简单单的建立一个通道,后来给服务器和客户端加界面时,才发现自己并没有真正的掌握这些知识,胡哥刚讲完同步画板时,吕旭当天上午就实现了,而我觉得好高深啊,怎么实现的???虽然有些交流可总觉得自己还没入门。那两天真是不知道天天在写什么,有时听得懂被人讲的,看得懂别人的代码,就是自己不会写。。。(用某人的话说这些没有意义)

    周二早上怀着惴惴不安的心情来到公司,因为没写完作业,周一休息,不会写也不怎么想写,(不会俩字很敏感)书上代码敲了一遍,敲完基本什么也没记住。。。周二上午没讲课,大神李伟给我仔仔细细分析了框架,说了大略思路,唉,觉得自己明白了,开悟了。。。

   为了给设计程序一个良好的框架,胡哥给我们讲了UML作图,这个的话,如老师所说,框架很详细的话,只往框架中填代码就好了,“初中生培训三个月就可以完成”。。。可是我觉得大道至简,其实书设计思路不够熟练于是框架就变成了这样

  服务器框架

 客户端框架



  服务器客户端界面通信

大概讲,服务器要有3个方法

ServerSocket so=new ServerSocket(port);

 

//读取数据
	private String readString(InputStream ins) throws IOException{
		//创建一个字符串缓冲区
		StringBuffer stb=new StringBuffer();
		char c=0;
		while(c!=35){
			//遇到#号算一个字符串
			int i=ins.read();//读取客户机发过来的一个字节
			c=(char)i;//将输入的字节转换为一个char
			stb.append(c);
		}
		//将读到的字节转化为字符串,并调用trim去掉尾部的空格
		String inputS=stb.toString().trim();
		return inputS;
	}
	区分客户端发给服务器,还是群发,加了个标志值(c)
	int c=ins.read();
		if(c==1){//只发给服务器
			String inputS=readString(ins);
			while(!inputS.equals("bye")){
				System.out.println("客户机说"+inputS);
				//加到空白区域
				are.setText(are.getText()+"\r\n"+inputS);
				inputS=readString(ins);//读取客户机下一次输入
			}
		}else if(c==2){//发送给系统
			String inputS=readString(ins);
			while(!inputS.equals("bye")){
				System.out.println("客户机说"+inputS);
				//加到空白区域
				are.setText(are.getText()+"\r\n"+inputS);
				//群发给其他客户端
				StartListener.sendMsg(inputS);
				inputS=readString(ins);//读取客户机下一次输入
			}
		}

 

//发送消息给连接我的客户端
	public  void sendMsg2Me(String msg){
		try{
		msg+="#";
		out.write(msg.getBytes());
		}catch(Exception ef){
			ef.printStackTrace();
		}
	}

 这3个方法可能分布在不同的类中,类与类之间也因此相互连接

客户端与服务器端相对应,方法也相对应

       

Socket client=new Socket("IP",port);

 

public void  Connect(){
		
		try{
			ous=so.getOutputStream();//获取输出流
			System.out.println("服务器连接成功!");
			while(true){
				//读取服务器发来的消息
				ins=so.getInputStream();//获取输入流
				String message="";
				int b = ins.read();
				while(b!=35){
					//#号结尾
					message +=(char)b;
					b = ins.read();
				}
				//显示在客户端的area上
				are.setText(are.getText()+"\r\n"+message);
				System.out.println("服务器传过来的是="+message);
			}
		
		}catch(Exception e){
			e.printStackTrace();
		}
	}

 

//发送消息
	public  void sendMsg(String s){
		byte [] by=s.getBytes();
		try {
			ous.write(by);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

 最后效果

1.客户端发给服务器

 2.客户端群发



 3.一行代码解决汉字乱码

//读取汉字

message=new String(message.getBytes("ISO-8859-1"),"GB2312");



 

其实关于服务器与客户端的读写,在做同步画板时更能深刻体现,一边写进去什么dou.writeInt(),另一边就即读取什么dis.readInt();

					x2=e.getX();
					y2=e.getY();
					 if(s.equals("画线")){
						g.drawLine(x1, y1, x2, y2);
						try{
						dos.writeInt(1);
						dos.writeInt(x1);
						dos.writeInt(y1);
						dos.writeInt(x2);
						dos.writeInt(y2);
						System.out.println("x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2);
						}catch(Exception e1){
							e1.printStackTrace();
						}
					}else if(s.equals("画圆")){
						int r1=Math.abs(x2-x1);
						int r2=Math.abs(y2-y1);
						g.drawOval(x1, y1, r1, r2);
						try{
						dos.writeInt(2);
						dos.writeInt(x1);
						dos.writeInt(y1);
						dos.writeInt(r1);
						dos.writeInt(r2);
						System.out.println("x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2);
						}catch(Exception e1){
							e1.printStackTrace();
						}
					}else if(s.equals("画图")){
						ImageIcon con=new ImageIcon("images/psb.jpg");
						//缓冲图纸,实为窗体性质
						image01=new BufferedImage(con.getIconWidth(),con.getIconHeight(),BufferedImage.TYPE_INT_RGB);
						Graphics g2=image01.getGraphics();
						g2.drawImage(con.getImage(), 0, 0, null);
						//白纸划到窗体上
						g.drawImage(image01, 0, 0, null);
						try{
							int width=image01.getWidth();
							int height=image01.getHeight();
							dos.writeInt(3);
							dos.writeInt(width);
							dos.writeInt(height);
							//把每个像素点的颜色写进去
							for(int i=0;i<width;i++){
								for(int j=0;j<height;j++){
									dos.writeInt(image01.getRGB(i, j));
								}
							}
						}catch(Exception e1){
							e1.printStackTrace();
						}
					}

 

//读出数据的方法
	public void readMsg(InputStream ins){
		try {
			while(true){
				DataInputStream dis=new DataInputStream(ins);
				int type=dis.readInt();
				if(1==type){
				//读取客户端画线的数据
				int x1=dis.readInt();
				int y1=dis.readInt();
				int x2=dis.readInt();
				int y2=dis.readInt();
				System.out.println("x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2);
				g.drawLine(x1,y1,x2,y2);
				}else if(2==type){
					//读取客户端画圆的数据
					int x1=dis.readInt();
					int y1=dis.readInt();
					int r1=dis.readInt();
					int r2=dis.readInt();
					g.drawOval(x1, y1, r1, r2);
				}else if(3==type){
					//读取客户端画图的数据
					int width=dis.readInt();
					int height=dis.readInt();
					for(int i=0;i<width;i++){
						for(int j=0;j<height;j++){
							g.setColor(new Color(dis.readInt()));
							g.drawLine(i, j, i, j);
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

 

最终同步画板的效果



 

 

 在写客户端时用了鼠标监听器和事件监听器都为内部类,内部类最大的好处是基本上省略了传参过程,节省很多代码,最大的缺点是不清晰,在编程语言类往往讲究清晰第一,在写服务器端是鼠标监听器和时间监听器均是外部类,尝试了一下,过程中出现过空指针,但都不是什么大问题,容易解决。在写的过程中还犯了个错误,用了static的一个getter方法,导致同步时服务器只能同步客户端的一条线,原因是第二个调用getter方法覆盖了前一次的数据,static用时需谨慎和思路很清晰啊。。。。。

 

  • 大小: 13.8 KB
  • 大小: 30.6 KB
  • 大小: 4.7 KB
  • 大小: 5.6 KB
  • 大小: 84.2 KB
  • 大小: 19.1 KB
  • 大小: 129.4 KB
  • 大小: 33.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics