黑马程序员—网络编程II

TCP网络编程

示例代码:上传文件,多客户端上传,并且保证不会因为文件的名称而重复

为了可以让多个客户端同时并发访问服务端。
那么服务端最好就是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。

定义线程:只要明确了每一个客户端要在服务端执行的代码即可,将该代码存入run方法中。

为区别不同的客户端上传内容,用客户端ip+第几次上传表示上传文件名,所以run方法里定义计数器。

class PicThread implements Runnable
{
	private Socket s;
	PicThread(Socket s)
	{
		this.s = s;
	}
	public void run()
	{
		int count = 1;
		String ip  = s.getInetAddress().getHostAddress();
		try
		{
			System.out.println(ip+"....connected");
			InputStream in = s.getInputStream();
			File dir =  new File("d:\\pic");
			File file = new File(dir,ip+"("+(count)+")"+".jpg");
			while(file.exists())
				file = new File(dir,ip+"("+(count++)+")"+".jpg");
			FileOutputStream fos = new FileOutputStream(file);
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=in.read(buf))!=-1)
			{
				fos.write(buf,0,len);
			}
			OutputStream out = s.getOutputStream();
			out.write("上传成功".getBytes());
			fos.close();
			s.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"上传失败");
		}
	}
}

客户端:利用主方法参数args接受文件路径,再利用File对象做一系列是否可执行操作的判断。

然后建立socket对象,进行数据传输,最后获取服务端通知,关闭socket

class  PicClient
{
	public static void main(String[] args)throws Exception 
	{
		if(args.length!=1)
		{
			System.out.println("请选择一个jpg格式的图片");
			return ;                                                                              		         }
		File file = new File(args[0]);
		if(!(file.exists() && file.isFile()))
		{
			System.out.println("该文件有问题,要么补存在,要么不是文件");
			return ;
		}
		if(!file.getName().endsWith(".jpg"))
		{
			System.out.println("图片格式错误,请重新选择");
			return ;
		}
		if(file.length()>1024*1024*5)
		{
			System.out.println("文件过大,没安好心");
			return ;
		}
		Socket s = new Socket("192.168.1.254",10007);
		FileInputStream fis = new FileInputStream(file);
		OutputStream out = s.getOutputStream();
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=fis.read(buf))!=-1)
		{
			out.write(buf,0,len);
		}
		//通知服务端数据已写完
		s.shutdownOutput();
		InputStream in = s.getInputStream();
		byte[] bufIn = new byte[1024];
		int num = in.read(bufIn);
		System.out.println(new String(bufIn,0,num));
		fis.close();
		s.close();
	}
}

服务端:利用线程启动服务

class  PicServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10007);
		while(true)
		{
			Socket s = ss.accept();
			new Thread(new PicThread(s)).start();
		}
	}
}

示例代码:客户端并发登

需求:客户端通过键盘录入用户名,服务端对这个用户名进行校验。
如果该用户存在,在服务端显示xxx,已登陆,并在客户端显示 xxx,欢迎光临。
如果该用户存在,在服务端显示xxx,尝试登陆,并在客户端显示 xxx,该用户不存在。
最多登录三次。

客户端:用for循环判断3次登陆限制

class  LoginClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.254",10008);
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
		for(int x=0; x<3; x++)
		{
			String line = bufr.readLine();
			if(line==null)
				break;
			out.println(line);
			String info = bufIn.readLine();
			System.out.println("info:"+info);
			if(info.contains("欢迎"))
				break;
		}
		bufr.close();
		s.close();
	}
}


定义线程:同样for循环,定义一个判断标记flag,如果用户名存在就为真。

class UserThread implements Runnable
{
	private Socket s;
	UserThread(Socket s)
	{
		this.s = s;
	}
	public void run()
	{
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connected");
		try
		{
			for(int x=0; x<3; x++)
			{
				BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
				String name = bufIn.readLine();
				if(name==null)
					break;
				BufferedReader bufr = new BufferedReader(new FileReader("user.txt"));
				PrintWriter out = new PrintWriter(s.getOutputStream(),true);
				String line = null;
				boolean flag = false;
				while((line=bufr.readLine())!=null)
				{
					if(line.equals(name))
					{
						flag = true;
						break;
					}				
				}
				if(flag)
				{
					System.out.println(name+",已登录");
					out.println(name+",欢迎光临");
					break;
				}
				else
				{
					System.out.println(name+",尝试登录");
					out.println(name+",用户名不存在");
				}
			}
			s.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"校验失败");
		}
	}
}

服务端:

class  LoginServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10008);
		while(true)
		{
			Socket s = ss.accept();
			new Thread(new UserThread(s)).start();
		}
	}
}
类URL

通常,URL 可分成几个部分:包括协议,域名或者ip+端口,请求内容的相对路径,键值对形式存在的请求参数。
URL 可选择指定一个“端口”,它是用于建立到远程主机TCP 连接的端口号。如果未指定该端口号,则使用协议默认的端口。例如,http 协议的默认端口为80。

关键方法:

String getFile()  获取此 URL 的文件名。
String getHost()  获取此 URL 的主机名。
String getPath()  获取此 URL 的路径部分。
int getPort()  获取此 URL 的端口号。
String getProtocol()  获取此 URL 的协议名称。
String getQuery()  获取此 URL 的查询部。
URLConnection openConnection()
          返回一个 URLConnection 对象,它表示到URL 所引用的远程对象的连接。
InputStream openStream()
          打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。

抽象类URLConnection:是所有类的超类,它代表应用程序和URL之间的通信链接。此类的实例可用于读取和写入此URL 引用的资源。                                                                 

通常通过在URL 上调用openConnection 方法创建连接对象。                                     

由于该类封装了socket,所以不用自己建立socket进行连接,并且可以直接调用getInputStream()和getOutputStream()方法。

示例代码:

class  URLConnectionDemo
{
	public static void main(String[] args) throws Exception
	{
		URL url = new URL("http://127.0.0,1:8080/myweb/demo.html");
		URLConnection conn = url.openConnection();
		InputStream in = conn.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf,0,len));
	}
}

代码实例:利用URL和URLConnection自制IE浏览器

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class  MyIEByGUI
{
	private Frame f;
	private TextField tf;
	private Button but;
	private TextArea ta;
	private Dialog d;
	private Label lab;
	private Button okBut;
	MyIEByGUI()
	{
		init();
	}
	public void init()
	{
		f = new Frame("my window");
		f.setBounds(300,100,600,500);
		f.setLayout(new FlowLayout());
		tf = new TextField(60);
		but = new Button("转到");
		ta = new TextArea(25,70);

		d = new Dialog(f,"提示信息-self",true);
		d.setBounds(400,200,240,150);
		d.setLayout(new FlowLayout());
		lab = new Label();
		okBut = new Button("确定");
		d.add(lab);
		d.add(okBut);

		f.add(tf);
		f.add(but);
		f.add(ta);

		myEvent();
		f.setVisible(true);
	}
	private void  myEvent()
	{
		okBut.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				d.setVisible(false);
			}
		});
		d.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				d.setVisible(false);
			}
		});
		tf.addKeyListener(new KeyAdapter()
		{
			public void keyPressed(KeyEvent e)
			{
				try
				{
				    if(e.getKeyCode()==KeyEvent.VK_ENTER)
					showDir();
				}
				catch (Exception ex)
				{
				}
			}
		});
		but.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				try
				{
					showDir();
				}
				catch (Exception ex)
				{
				}
				
			}
		});
		f.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);	
			}
		});
	}
	private void showDir()throws Exception
	{
		ta.setText("");
		String urlPath = tf.getText();                                                                                 		URL url = new URL(urlPath);
		URLConnection conn = url.openConnection();
		InputStream in = conn.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		ta.setText(new String(buf,0,len));
	}
	public static void main(String[] args) 
	{
		new MyIEByGUI();
	}
}



 

                      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值