Socket(1)

端口号可以从0~65535:

今天就写TCP相关。在下一节我会分别写有关UDP,还有MultiCastSocket。

Socket的工作原理:

通信两端都建立一个Socket,从而两端形成虚拟链路。通过IO流完成网络通信。

实现两台终端进行通信需使用IP地址与port。

InetAddress:可获取IP地址 & 主机名的类

实例:

import java.io.IOException;
import java.net.InetAddress;

public class InetAnddressTest {
    public static void main(String[] args) throws IOException {
        InetAddress ip = InetAddress.getByName("www.baidu.com");
        System.out.println(ip.getHostAddress());
        System.out.println(ip.getHostName());
        System.out.println("isReachable:"+ip.isReachable(5000));

        InetAddress ip2 = InetAddress.getLocalHost();
        System.out.println(ip2.getHostAddress());
        System.out.println(ip2.getHostName());
        System.out.println("isReachable:"+ip2.isReachable(5000));
    }
}

先了解TCP

当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体的确认信息(握手)。如果没有收到,则会再次发送刚才发送的信息。建立虚拟链路之前必须有一个主动接受来自其他通信实体的连接请求。即ServerSocket。

ServerSocket(上图右边的)【服务端】:

ServerSocket(int port):用端口来创建一个ServerSocket,此时localAddress为默认为服务ip。如果有终端有多个ip(多网卡)时可以用带ip参数的构造方法。

accept():等待接受Socket的连接请求,返回一个发送连接请求的客户端socket对象。

getInputStream()/ getOuptStream():获取输入输出流来完成读写操作。

Socket(上图左边的)【客户端】:

Socket(InetAddress/String remoteAddress,int port):指定服务器的ip地址,端口号。

  *如果new了一个客户端Socket将会连接到服务端。即accept方法返回socket。

getInputStream()/ getOuptStream():获取输入输出流来完成读写操作。

SetTimeOut(int timeout):当超出限定时间会抛出SocketTimeoutException异常。

  *s.connconnect(new InetAddress(host,port),1000):连接中可以设定连接超时。

实例:

服务端代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {

    public static List<Socket> clients = new ArrayList<Socket>();

    public static void main(String[] args) {
        int port = 1025;
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                Socket client = serverSocket.accept();
                clients.add(client);
                new Thread(new Client(client)).start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static class Client implements Runnable {
        Socket client;
        BufferedReader br;

        public Client(Socket client) throws IOException {
            this.client = client;
            br = new BufferedReader(new InputStreamReader(
                    client.getInputStream()));
        }

        public String read() {
            try {
                return br.readLine();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                clients.remove(client);
            }
            return null;

        }

        public void run() {
            // TODO Auto-generated method stub
            try {

                String msg = null;
                while ((msg = read()) != null) {
                    for (Socket s : clients) {
                        PrintStream pw = new PrintStream(s.getOutputStream());
                        pw.println(msg);
                        System.out.println(msg);
                    }
                }
                br.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
            }

        }
    }

}

客户端代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;

public class Client{

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        String ip = InetAddress.getLocalHost().getHostAddress();
        int port = 1025;
        Socket socket = new Socket(ip, port);
        new Thread(new ClientReceiver(socket)).start();

        PrintStream pw = new PrintStream(socket.getOutputStream());
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String msg = null;
        while ((msg = br.readLine()) != null) {
            pw.println(msg);
        }
    }

    public static class ClientReceiver implements Runnable {
        Socket client;
        BufferedReader br;

        public ClientReceiver(Socket client) throws IOException {
            this.client = client;
            br = new BufferedReader(new InputStreamReader(
                    client.getInputStream()));
        }

        public void run() {
            // TODO Auto-generated method stub
            try {
                String msg = null;
                while ((msg = br.readLine()) != null) {
                    System.out.println(msg);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

运行:

  1. 先运行Server再运行Client
  2. 在Client中输入你要传送的文字。

以上是堵塞式网络通信,所以需要创建线程去完成。非堵塞式NIO可以让服务器使用一个或有限几个线程来同时处理连接到服务器上的所有客户端。

通道Socket:

在NIO涉及到几个重要的:Channel(通道),Buffer(缓冲区),Selector(选择器)。

NIO是双向的,需要Channel来完成读写操作,然而Channel是由Selector来管理。 读取或写入的,为了高效操做读写用到Buffer。

通过SocketChannel,以TCP来向网络连接的两端读写数据;

通过ServerSocketChanel能够监听客户端发起的TCP连接,并为每个TCP连接创建一个新的SocketChannel来进行数据读写;

通过DatagramChannel,以UDP协议来向网络连接的两端读写数据。

实例:

服务端代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class MyNioServer {

    protected Selector selector;
    static int BufferSize = 2 * 1024;
    protected ByteBuffer clientBuffer = ByteBuffer.allocate(BufferSize);
    ServerSocketChannel server;

    public MyNioServer(int port) throws IOException {
        selector = this.getSelector(port);

    }

    // 获取Selector
    protected Selector getSelector(int port) throws IOException {
        Selector sel = Selector.open();
        server = ServerSocketChannel.open();
        server.socket().bind(new InetSocketAddress("localhost", port));
        server.configureBlocking(false);
        server.register(sel, SelectionKey.OP_ACCEPT);
        return sel;
    }

    // 监听端口
    public void listen() {
        try {
            /*
             * 我们调用 Selector 的 select() 方法。这个方法会阻塞,直到至少有一个已注册的事件发生。
             * 当一个或者更多的事件发生时, select() 方法将返回所发生的事件的数量。该方法必须首先执行。
             */
            while (selector.select() > 0) {
                    Iterator iter = selector.selectedKeys().iterator();
                    while (iter.hasNext()) {
                        /*
                         * 在处理 SelectionKey 之后,我们必须首先将处理过的SelectionKey 从选定的键集合中删除。
                         * 如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键出现,这会导致我们尝试再次处理它。
                         * 我们调用迭代器的 remove() 方法来删除处理过的 SelectionKey:iter.remove();
                         */
                        SelectionKey key = (SelectionKey) iter.next();
                        iter.remove();
                        process(key);
                    }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 处理事件
    protected void process(SelectionKey key) throws IOException {
        if (key.isAcceptable()) { // 接收请求
            SocketChannel channel = server.accept();
            // 设置非阻塞模式
            channel.configureBlocking(false);
            //注册读动作
            channel.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) { // 读信息
            SocketChannel channel = (SocketChannel) key.channel();
            if (channel.read(clientBuffer) > 0) {
                // 重设此缓冲区,将限制设置为当前位置,然后将当前位置设置为0
                clientBuffer.flip();
                byte[] data = clientBuffer.array();
                System.out.println(new String(data).trim());
                clientBuffer.clear();
            }
            //注册写动作
            SelectionKey sKey = channel.register(selector,SelectionKey.OP_WRITE);
            //传递写对应的附件(值)
            sKey.attach("hello! i am server!");
        } else if (key.isWritable()) { // 写信息
            SocketChannel channel = (SocketChannel) key.channel();
            String name = (String) key.attachment();
            clientBuffer.put(name.getBytes());
            clientBuffer.flip();
            channel.write(clientBuffer);
            clientBuffer.clear();
            // 不加close会无限循环
            channel.close();
        }

    }

    public static void main(String[] args) {
        int port = 8888;
        try {
            MyNioServer server = new MyNioServer(port);
            server.listen();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class MyNioClient {

    static InetSocketAddress ip = new InetSocketAddress("localhost", 8888);

    static class Message implements Runnable {
        String msg = "";

        public Message(String msg) {
            this.msg = msg;
        }

        public void run() {
            try {
                // 打开Socket通道
                SocketChannel client = SocketChannel.open();
                // 打开选择器
                Selector selector = Selector.open();
                // 设置为非阻塞模式
                client.configureBlocking(false);
                // 注册连接服务端socket动作
                client.register(selector, SelectionKey.OP_CONNECT);
                // 连接
                client.connect(ip);
                // 分配内存
                ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
                while (selector.select() > 0) {
                    Iterator iter = selector.selectedKeys().iterator();
                    while (iter.hasNext()) {
                        SelectionKey key = (SelectionKey) iter.next();
                        iter.remove();
                        if (key.isConnectable()) {
                            SocketChannel channel = (SocketChannel) key
                                    .channel();
                            if (channel.isConnectionPending())
                                channel.finishConnect();
                            buffer.put(msg.getBytes());
                            buffer.flip();
                            channel.write(buffer);
                            buffer.clear();
                            key.interestOps(SelectionKey.OP_READ);
                        } else if (key.isReadable()) {
                            SocketChannel channel = (SocketChannel) key
                                    .channel();
                            buffer.clear();
                            int count = channel.read(buffer);
                            if (count > 0) {
                                buffer.flip();
                                msg = "";
                                while (buffer.remaining() > 0) {
                                    byte b = buffer.get();
                                    msg += (char) b;

                                }
                                System.out.println(msg);
                                buffer.clear();
                            } else {
                                client.close();
                                break;
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new Thread(new Message("hello! i am client!")).start();
    }
}

运行:

  1. 先运行Server再运行Client
时间: 2024-10-12 14:59:03

Socket(1)的相关文章

使用 IDEA 创建 Maven Web 项目 (异常)- Disconnected from the target VM, address: &#39;127.0.0.1:59770&#39;, transport: &#39;socket&#39;

运行环境: JDK 版本:1.8 Maven 版本:apache-maven-3.3.3 IDEA 版本:14 maven-jetty-plugin 配置: <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <configuration> <webAppSourceDirectory>${pro

iOS开发——网络编程OC篇&amp;Socket编程

Socket编程 一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象: 传输层.会话层.表示层和应用层则被称作主机层,是用户所面向和关心的内容. http协议   对应于应用层 tcp协议    对应于传输层 ip协议     对应于网络层 三者本质上没有可比性.  何况HTTP协议是基于TCP连接的. TCP/IP是传输层协议,主要

winform学习日志(二十三)---------------socket(TCP)发送文件

一:由于在上一个随笔的基础之上拓展的所以直接上代码,客户端: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using Sys

程序媛计划——python socket通信

定义 socket 是进程间的一种通信方式,可以实现不同主机间的数据传输 #写服务期端程序server.py #实现服务器向客户端连接 1 #!/usr/bin/env python 2 #coding:utf-8 3 import socket 4 s= socket.socket() 5 #127.0.0.1是本地主机,1234是随意设置到一个端口号 6 s.bind(('127.0.0.1',1234)) #绑定端口号为1234 7 8 #等待客户端连接 9 s.listen(5) 10

Linux Socket编程-(转自吴秦(Tyler))

"一切皆Socket!" 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. --有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠socket?那什么是socket?socket的类型有哪些?还有socket的基本函数,这些都是本文想介绍的.本文的主要内容如下: 1.网络中进程之间如何通信?

java socket编程中backlog的含义(zz)

使用Java.NET.ServerSocket能够方便的创建一个服务端套接字,这个类的构造函数有一个参数backlog.下面这段代码,在本机的8888端口上建立了一个套接字,backlog设置为5. [java] view plain copy // port:8888,backlog:5 ServerSocket server = new ServerSocket(8888, 5); 下面的Client是我们的测试类,会创建30个socket连接. [java] view plain copy

Python Socket 编程——聊天室演示样例程序

上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket 编程的理解. 聊天室程序需求 我们要实现的是简单的聊天室的样例,就是同意多个人同一时候一起聊天.每一个人发送的消息全部人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天.例如以下图: 图来自:http://www.ibm.com/developerworks/linux/tu

【windows socket+UDPserverclient】

Windows Socket+UDPserverclient Winsock是 Windows下套接字标准.                    1.UDP socket编程:          UDP(用户数据报协议)是一个无连接.不可靠的传输数据,其特点是简单,快捷.相比与TCP,UDP不须要建立连接(不需connect.accept函数),数据发送接收之后,不须要终止连接.基于UDP的程序,避免了TCP执行的开销,在效率与速度上具有更好的表现.          UDP是无连接的,可能会

Unity3d 封装Socket创建简单网络

北京又在打雷下大雨了,学习Unity以来,越来越感兴趣,情不自禁的想要学习更多知识 这次自己搭建一个Socket模块,比较基础,适合新手学习,详细介绍Socket的搭建过程,同样会把详细过程在代码里进行注释~ 在搭建Socket过程中,需要创建以下几个常用的方法: 1.创建套接字(socket) 2.绑定Ip和端口 3.监听方法 4.接收客户端请求的方法 5.收发消息的方法 创建SocketManger管理类 把客户端与服务端代码都写在新建的SocketManger里,并把SocketMange

Java网络编程之tcp的socket通信

1.客户端MyClient.java 1 import java.io.*; 2 import java.net.*; 3 4 public class MyClient 5 { 6 public static void main(String[] args)throws Exception 7 { 8 Socket s = new Socket("192.168.1.1" , 30000); 9 // 客户端启动ClientThread线程不断读取来自服务器的数据 10 new Th