网络编程


1在网络中,两台机器为了进行通信。首先需要建立一个网络通路,然后它们之间才能够进行通信。


2 Tcp和Udp的区别

udp:
将数据及源和目的封装成数据包中,不需要建立连接
每个数据包的大小限制在64K内
因无连接,是不可靠的协议
不需要建立连接,速度快

Tcp
建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议

必须建立连接,效率会稍低


3使用UDP实现的一个能够聊天的小程序

package com.Socket;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * 使用UDP的方式进行聊天
 * <p/>
 * “收消息”和“发消息”的动作要能够同时进行,所以我们需要使用“多线程”的技术
 * 起一个单独的线程负责“收消息”,另一个线程负责“发送消息”
 * User: OF895
 * Date: 2014/12/3
 * Time: 23:59
 */
public class ChatByUdp {
    public static void main(String[] args) throws Exception {
        //这里我们首先为下面的线程提供一个“socket"套接字,当然我们也可以写死在下面的收发消息的类中
        DatagramSocket sendSocket = new DatagramSocket();
        DatagramSocket receiveSocket = new DatagramSocket(10002);

        //开启两个线程,执行动作
        new Thread(new SendMessage(sendSocket)).start();
        new Thread(new ReciveMessage(receiveSocket)).start();
    }

}

class SendMessage implements Runnable {

    //使用“构造函数”,传入一个upd的socket套接字,用于进行udp编程
    private DatagramSocket datagramSocket;

    public SendMessage(DatagramSocket datagramSocket) {
        this.datagramSocket = datagramSocket;
    }

    @Override
    public void run() {
        try {
            //1读取键盘录入的信息
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            while ((line = br.readLine()) != null) {
                if("over".equals(line)){
                     break;
                }
                byte[] bytes = line.getBytes();
                //2创建UDP数据包
                DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length, InetAddress.getByName("127.0.0.1"), 10002);
                //因为udp是不需要建立连接,就可以发送数据的,那么我们直接发送数据
                datagramSocket.send(dp);
                System.out.println(Thread.currentThread().getName());
            }

        } catch (Exception e) {
            throw new RuntimeException("发送消息发生异常!");
        }
    }
}

class ReciveMessage implements Runnable {
    private DatagramSocket datagramSocket;

    public ReciveMessage(DatagramSocket datagramSocket) {
        this.datagramSocket = datagramSocket;
    }

    @Override
    public void run() {
        try {

            //这边使用一个“循环”不停的去接受发送端,发过来的数据
            while (true) {
                byte[] buf = new byte[1024];
                //创建一个数据包,带有缓冲字节数组,用于接受从“发送端”发送过来的数据
                DatagramPacket dp = new DatagramPacket(buf, buf.length);
                //使用datagramSocket“接受”到向这个端口发来的消息,并且通过DatagramPacket存放到buf这个字节数组中
                datagramSocket.receive(dp);
                String ip = dp.getAddress().getHostAddress();
                String data = new String(dp.getData(), 0, dp.getLength());
                System.out.println(Thread.currentThread().getName() + ",ip = " +ip + ":" + data);
            }

        } catch (Exception e) {
            throw new RuntimeException("接收消息发生异常!");
        }
    }
}

运行结果:

hello
Thread-0
Thread-1,ip = 127.0.0.1:hello
nihao
Thread-0
Thread-1,ip = 127.0.0.1:nihao
hehe
Thread-0
Thread-1,ip = 127.0.0.1:hehe


4使用Tcp进行实现的一个小例子

使用TCP/IP进行“客户机”的数据(mp3,文本,图像)传输到“服务器”上。未使用线程,一对一。这个用的是字节传输数据。没有使用缓冲。注意与下面程序的区别。
客户端程序:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class TextClient
{

	/**
	 * 客户端。这里讲一个“文件”,传输到“服务器”端。
	 * @param args
	 */
	public static void main(String[] args)
	{
		FileInputStream fis = null;
		Socket s = null;
		OutputStream  os = null;
		//1启动socket服务
				try
				{
					s = new Socket("192.168.0.131",10005);
					fis = new FileInputStream("c:\\1.mp3");
					 os = s.getOutputStream();
					byte[] buf = new byte[1024];
					int len = 0;
					while((len = fis.read(buf)) != -1)
					{
						os.write(buf, 0, len);
						os.flush();
					}
					s.shutdownOutput();
					InputStream is  = s.getInputStream();
					byte[] bufIn = new byte[1024];
					is.read(bufIn);//从输入流中读取一定数量的字节,并将其存储在缓冲区数组 bufIn中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。
					//也就是从socket流中读取“服务器”端发过来的“歌曲上传成功”这么一句话。缓存到字节数组bufIn中。
					String str = new String(bufIn,0,bufIn.length);//将字节数组转换为“字符串”。
					System.out.println(str);
				}
				catch (UnknownHostException e)
				{
					System.out.println("IP地址有误");
					e.printStackTrace();
				}
				catch (IOException e)
				{
					System.out.println("输出异常");
					e.printStackTrace();
				}
				try
				{
					//这里关闭流资源的时候,需要注意一下。
					fis.close();
					os.close();
					s.close();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				

	}

}

服务器端程序:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class TextServer
{

	/**
	 * “客户端”和“服务器”端进行“数据”传输(包括,图片,mp3,文本等文件)
	 * 这个没有使用线程,是一对一的。
	 * @param args
	 */
	public static void main(String[] args)
	{
		Socket s = null;
		ServerSocket ss = null;
		FileOutputStream fos = null;
		try
		{
			ss = new ServerSocket(10005);//这边的“客户机”连接“服务器”,我们需要单独try catch下。如果没连上下面的代码就不需要执行了。
			s = ss.accept();
			String ip = s.getInetAddress().getHostAddress();
			System.out.println("ip:"+ ip + "...........has connected!");
			
		}
		catch (IOException e)
		{
			System.out.println("客户机没有连接上服务器");
			e.printStackTrace();
		}
		
		try
		{
			fos = new FileOutputStream("c:\\server.mp3");
			InputStream  is = s.getInputStream();
			byte[] buf = new byte[1024];
			int len = 0;
			while((len = is.read(buf)) != -1)
			{
				fos.write(buf, 0, len);
				fos.flush();
			}
			OutputStream  os = s.getOutputStream();
			String str = "歌曲上传成功";
			byte[] bufOs = str.getBytes();//这里讲str这句话转换成字节数组,存入字节数组中。不要写成byte[] bufos = new byte[1024];
			os.write(bufOs);//这一句等同于os.write(bufos,0,bufos.length);效果是相同的,翻看api文档。作用是将 bufos.length 个字节从指定的 byte数组写入此(这里指socket的outputstream)输出流.
		}
		catch (IOException e)
		{
			System.out.println("输入输出有误!");
			e.printStackTrace();
		}
		
		try
		{
			fos.close();
			s.close();
			ss.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		

	}

}

5使用Tcp的小例子2:

利用“线程”和“死循环”实现多个“客户端”向“服务器”端发送消息。基于TCP/IP协议传输。这个使用了缓冲技术。
客户端代码:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class TcpClient
{

	/**
	 * “客户端”向“服务器”端发送“字符”。在“服务器”端显示到控制面板上。
	 * 
	 * @param args
	 */
	public static void main(String[] args)
	{
		Socket s = null;
		BufferedReader br = null;
		BufferedWriter bw = null;
		try
		{
			s = new Socket("192.168.0.131",10007);
			br = new BufferedReader(new InputStreamReader(System.in));
			bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
			String len = null;
			while((len = br.readLine()) != null)
			{
				bw.write(len);
				bw.newLine();//这个用于换行
				bw.flush();
			}
			s.shutdownOutput();
		}
		catch (UnknownHostException e1)
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		catch (IOException e1)
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
			try
			{
				
				s.close();
				
			}
			catch (IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
			
	}

}

服务器端代码:
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer
{

	/**这个是服务器端,接受从“客户端”发送过来的信息。
	 * 这里讲ss.accept()方法是用了一个“死循环”,这样有一个“客户机”来连接
	 * “服务器”就连接一次。这样就实现了多个客户机与“服务器”通讯。(单向的,从客户机到服务器)
	 * 这里有个注意点需要主意一下,我们需要将“客户机”发送过来的信息,在服务器端显示在控制台上。
	 * 这个动作我们需要封装到一个单独的线程中。
	 * 	
	 * * @param args
	 */
	public static void main(String[] args)
	{
		ServerSocket ss = null;
		Socket s = null;
		BufferedReader br = null;
		BufferedWriter bw = null;
		try
		{
			 ss = new ServerSocket(10007);//在实际的操作中,我们通常会将ServerSocket ss = new ServerSocket(10007);的异常单独try catch一下。
			 while(true)
			 {
				 s = ss.accept();
				 
				 new Thread(new ClientAccept(s,br,bw)).start();
				 
			 }
			
			 
		}
		catch (IOException e)
		{
			System.out.println("客户端没有连上“服务器”端");
			e.printStackTrace();
		}
		
		try
		{
			s.close();
			ss.close();
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}
//单独封装一个线程,用来处理每个客户机,与服务器连接后,进行一些操作。
class ClientAccept implements Runnable
{
	Socket s = null;//需要将Socekt从TcpServer中带过来。
	BufferedReader br = null;
	BufferedWriter bw = null;
	public ClientAccept(Socket s,BufferedReader br,BufferedWriter bw)
	{
		this.s = s;
		this.br = br;
		this.bw = bw;		
	}

	@Override
	public void run()
	{
		try{
			String ip = s.getInetAddress().getHostAddress();
			 System.out.println("ip:"+ ip + "..............has connected!");
			InputStream is = s.getInputStream();
			 br = new BufferedReader(new InputStreamReader(is));//这里用到了“转换流”和“缓冲技术”。
			 bw = new BufferedWriter(new OutputStreamWriter(System.out));//把它输出到“控制台”上
			String len = null;
			while((len = br.readLine()) != null)
			{
				bw.write(len);
				bw.newLine();
				bw.flush();
			}
			
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		
	}
	
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值