Tcp与Udp

来源:互联网 发布:unctad数据库怎么用 编辑:程序博客网 时间:2024/06/05 14:46

数据在网路上传输,一般要遵守一些协议.而现实中最常见的网络传输协议莫过于tcp/ip协议.该协议将网络分成不同的层次,一般而言
,可分成:物理数据链路层,网路层,传输层,应用层.而今要讨论的Tcp/udp协议是属于传输层的协议.而与该协议密切相关的概念要数ip地址与计算机端口的概念.网路世界通过ip与端口,来实现逻辑上每台计算机的寻址,从而可以通讯,记住,这样的地址也只是逻辑上的寻址.置于如何寻址,请参考其他资料.
计算机通过寻址,找到了目标之后,就渴望通讯.而在通讯的过程中,就该传输层而言,要数TCp与udp最为常见.那么他们是怎样的通讯方式呢?

对于udp而言,其是面向无连接的协议,也就是说,双方通讯不需要两方同时建立联系.所以是一种不可靠的传输协议,但同时也是一种相对而言,传输速度比较快的协议.常常应用于局域网中,例如同步语音,同步视频等等.
而对于tcp而言,其是面向连接的协议,也就是说,双方通讯需要两方同时建立联系.所以是一种可靠的传输协议,但同时也是一种相对而言,传输速度比较慢的协议.

先介绍udp编程:
在java中,udp的编程主要用到了两个类:
DatagramSocket 通过ip地址与端口来创建套接字
DatagramPacket 在传输的过程中传递的数据包.可用来发送数据,
也可以用来接收数据.(通常开启一个独立的线程执行代码)
一段典型的代码片段:

发送端:

class Sender implements Runnable{    private DatagramSocket socket;    private Scanner scanner;    public Sender(){        try {            socket=new DatagramSocket(1000);            scanner=new Scanner(System.in);        } catch (SocketException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    @Override    public void run() {        // TODO Auto-generated method stub        try {            while(true){                System.out.println("开始输入:");                String line=scanner.nextLine();                DatagramPacket packet=new DatagramPacket(line.getBytes(),line.getBytes().length, InetAddress.getLocalHost(), 20000);                socket.send(packet);                if("bye".equals(line)){                   break;                }                Thread.sleep(500);            }        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally{            if(socket!=null){                socket.close();            }        }    }

接收端的代码:

class Reciver implements Runnable{    private DatagramSocket socket;    public Reciver(){        try {            socket=new DatagramSocket(20000);        } catch (SocketException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    @Override    public void run() {        // TODO Auto-generated method stub        try {            while(true){                byte[] buffer=new byte[1024];                DatagramPacket packet=new DatagramPacket(buffer, buffer.length);                socket.receive(packet);                String str=new String(buffer,0,packet.getLength());                System.out.println("接收到的数据:"+str);                if("bye".equals(str)){                    break;                }                Thread.sleep(500);            }        }  catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally{            if(socket!=null){                socket.close();            }        }    }

对于发送与接收方而言,在系统中申请端口,就可以发送与接收信息.
在发送的数据包中,不仅存放数据,而且需要指定数据传送的目标地址,即可.

接下来介绍Tcp简单编程.经典的tcp示例是简单的群聊系统.
思路:
对于我们客户而言,开启两个线程来不断的读写操作.
对于服务端,其中有链接的管理类,来负责链接的接收与移除.
当有链接建立时,开启新的线程来负责聊天转发.

注意:在这里,我将套接字的管理类设计成单例模式,而且在添加或者删除连接时,注意多线程的访问问题,设计成线程安全的.

在这里用代码实现:

客户端:

向服务器写入数据的线程:

/* * 向目标写数据 */class Writer implements Runnable{    private OutputStream os;    private PrintWriter pw;    private Scanner scanner;    public Writer(OutputStream os){        this.os=os;        pw=new PrintWriter(os);        scanner=new Scanner(System.in);    }    @Override    public void run() {        // TODO Auto-generated method stub        while(true){            System.out.println("开始写数据:");            String line=scanner.nextLine();            pw.println(line);            pw.flush();            if("bye".equals(line)){                pw.close();                break;            }        }    }}

向服务器读取数据的线程:

//从服务端读取数据class Reader implements Runnable{    private InputStream is;    private BufferedReader br;    public Reader(InputStream is){         this.is=is;         br=new BufferedReader(new InputStreamReader(is));    }    @Override    public void run() {        // TODO Auto-generated method stub        while(true){            try {                String line=br.readLine();                System.out.println(line);            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}

然后开启线程,进行读取与写入:

public class Client {    public static void main(String[] args) {        System.out.println("请输入要开启的端口号:(1024-65535)");        Scanner scanner=new Scanner(System.in);        String portStr=scanner.nextLine();        int port=Integer.parseInt(portStr);        Socket socket=null;        try {            socket=new Socket(InetAddress.getLocalHost(),20000,InetAddress.getLocalHost(),port);            /*             * 开启读写进程             */            new Thread(new Writer(socket.getOutputStream())).start();            new Thread(new Reader(socket.getInputStream())).start();        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }           }}

套接字的管理类:

/* * 设计成单例模式 */ /* */public class SocketManager {    private static List<Socket> list=new ArrayList<Socket>();    private static SocketManager manager;    private SocketManager(){    }    public static SocketManager getInstance(){        if(manager==null){            manager=new SocketManager();        }        return manager;    }    //添加连接    public void addSocket(Socket socket){        synchronized(list){            list.add(socket);        }    }    //移除连接    public void removeSocket(Socket socket){        synchronized(list){            list.remove(socket);        }    }    //返回所有的socket    public List<Socket> getAllSockets(){        return list;    }}

对于服务端:
等待接入的连接,开启转发线程:

public class Server {    private SocketManager manager;    private ServerSocket server;    public SocketManager getManager() {        return manager;    }    public ServerSocket getServer() {        return server;    }    public Server(){        manager=SocketManager.getInstance();        try {            server=new ServerSocket(20000);        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }     public static void main(String[] args) {         Server server=new Server();         ServerSocket Serversocket = null;         //不断的等待接入连接         try {            while(true){                 Serversocket=server.getServer();                 Socket socket=Serversocket.accept();                 //添加到管理器中                 server.getManager().addSocket(socket);                 new Thread(new Chart(socket)).start();            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally{            if(Serversocket!=null){                try {                    Serversocket.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }}

转发线程:

/* * 获取输入的内容,并将转发到其他的连接上 */class Chart implements Runnable{    private Socket socket;    private BufferedReader br=null;    private PrintWriter pw=null;    private SocketManager manager;    public Chart(Socket socket){        this.socket=socket;        try {            br=new BufferedReader(new InputStreamReader(socket.getInputStream()));        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        manager=SocketManager.getInstance();    }    @Override    public void run() {        // TODO Auto-generated method stub        try {            while(true){                String line=null;                while((line=br.readLine())!=null){                    System.out.println(socket.getInetAddress()+"说:"+line);                    for(int i=0;i<manager.getAllSockets().size();i++){                        Socket socket=manager.getAllSockets().get(i);                        if(socket!=this.socket){                            pw=new PrintWriter(socket.getOutputStream());                            pw.println(socket.getInetAddress()+"说:"+line);                            pw.flush();                        }                    }                }            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally{            manager.removeSocket(this.socket);        }    }}
0 0
原创粉丝点击