Java的Socket通讯基础编程完全指南_java

什么是Socket
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

Socket通讯的过程
Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
  (1) 创建Socket;
  (2) 打开连接到Socket的输入/出流;
  (3) 按照一定的协议对Socket进行读/写操作;
  (4) 关闭Socket.(在实际应用中,并未使用到显示的close,虽然很多文章都推荐如此,不过在我的程序中,可能因为程序本身比较简单,要求不高,所以并未造成什么影响。)

创建Socket
java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:

  Socket(InetAddress address, int port);
  Socket(InetAddress address, int port, boolean stream);
  Socket(String host, int prot);
  Socket(String host, int prot, boolean stream);
  Socket(SocketImpl impl)
  Socket(String host, int port, InetAddress localAddr, int localPort)
  Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
  ServerSocket(int port);
  ServerSocket(int port, int backlog);
  ServerSocket(int port, int backlog, InetAddress bindAddr)

  其中address、host和port分别是双向连接中另一方的IP地址、主机名和端 口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和 bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既可以用来创建serverSocket又可 以用来创建Socket。count则表示服务端所能支持的最大连接数。例如:学习视频网 http://www.xxspw.com

  Socket client = new Socket("127.0.01.", 80);
  ServerSocket server = new ServerSocket(80);

  注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才 能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。
  在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。

代码

server

   

 package socket; 

  import java.io.*;
  import java.net.*; 

  public class TcpServer {
    public static void main(String[] args) throws Exception {
      ServerSocket server = new ServerSocket(9091);
      try {
        Socket client = server.accept();
        try {
          BufferedReader input =
              new BufferedReader(new InputStreamReader(client.getInputStream()));
          boolean flag = true;
          int count = 1; 

          while (flag) {
            System.out.println("客户端要开始发骚了,这是第" + count + "次!");
            count++; 

            String line = input.readLine();
            System.out.println("客户端说:" + line); 

            if (line.equals("exit")) {
              flag = false;
              System.out.println("客户端不想玩了!");
            } else {
              System.out.println("客户端说: " + line);
            } 

          }
        } finally {
          client.close();
        } 

      } finally {
        server.close();
      }
    }
  }

client

  package socket; 

  import java.io.*;
  import java.net.*;
  import java.util.Scanner; 

  public class TcpClient {
    public static void main(String[] args) throws Exception {
      Socket client = new Socket("127.0.0.1", 9091);
      try {
        PrintWriter output =
            new PrintWriter(client.getOutputStream(), true);
        Scanner cin = new Scanner(System.in);
        String words; 

        while (cin.hasNext()) {
          words = cin.nextLine(); 

          output.println(words); 

          System.out.println("写出了数据: " + words);
        } 

        cin.close();
      } finally {
        client.close();
      }
    }
  } 

Server绑定ip

用c写socket的时候,struct sockaddr_in 结构体是可以指定sin_addr.s_addr的,也就是可以指定ip地址,为什么会有这种需求呢,例如我的网络链接是这样的:

我可能只想绑定eth0这个网卡的ip地址,因为我的lo和wlan0都可能在用一端口做了nginx的虚拟主机,因此在服务器端开启ServerSocket的时候,有指定ip的需求

方案
ServerSocket的一个构造函数如下:

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

参数:

    port - 本地 TCP 端口
    backlog - 侦听 backlog
    bindAddr - 要将服务器绑定到的 InetAddress

因为InetAddress无构造函数,我在这里纠结了好一段时间,查看stackoverflow上,可以使用InetAddress的getByName方法

示例代码

  InetAddress bindip = InetAddress.getByName("192.168.1.168"); 

  ServerSocket server = new ServerSocket(9091, 0, bindip); 

并发访问
服务器端通过增加多线程来同时处理多个客户端的请求,其实实现还是很水的,毕竟java对多线程封装也足够好了,我是在Server服务器端用一个内部类实现了Runnable接口,在run方法里处理客户端的请求,将数据打印出来

server代码

   

package capitalsocket; 

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

  public class CapitalizeServer {
    private static int clientNum = 0; 

    public static void main(String args[]) throws Exception {
      ServerSocket listener = new ServerSocket(9898, 0, InetAddress.getByName("192.168.1.168"));
      try {
        while (true) {
          Capitalizer multip = new Capitalizer(listener.accept(), CapitalizeServer.clientNum ++);
          Thread t = new Thread(multip);
          t.start();
        }
      } finally {
        listener.close();
      }
    } 

    private static class Capitalizer implements Runnable {
      private Socket client;
      private int id; 

      public Capitalizer(Socket s, int id) {
        this.client = s;
        this.id = id;
      } 

      public void run() {
        try {
          BufferedReader input =
              new BufferedReader(new InputStreamReader(this.client.getInputStream())); 

          while (true) {
            String data = input.readLine(); 

            if (data.equals("bye")) {
              System.out.println("当前第" + this.id + "个客户端度不想玩了!");
              break;
            } else {
              System.out.println("当前第" + this.id + "个客户端说:" + data);
            }
          } 

        } catch (IOException e) {
          e.printStackTrace();
        } finally {
          try {
            this.client.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      }
    } 

  }

client代码
客户端代码基本没变,增加了一个退出操作

   

package capitalsocket; 

  import java.io.PrintWriter;
  import java.net.Socket;
  import java.util.Scanner; 

  public class CapitalizeClient {
    public static void main(String[] args) throws Exception {
      Socket client = new Socket("192.168.1.168", 9898);
      try {
        PrintWriter output = new PrintWriter(client.getOutputStream(), true);
        Scanner cin = new Scanner(System.in);
        String words; 

        while (cin.hasNext()) {
          words = cin.nextLine();
          output.println(words); 

          if (words.equals("bye")) {
            break;
          } 

          // 每写一次数据需要sleep一会
          Thread.sleep(3000);
        } 

        cin.close();
      } finally {
        client.close();
      }
    }
  }

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
socket
c语言socket编程指南、java socket编程、java socket编程实例、java tcp socket编程、java多线程socket编程,以便于您获取更多的相关知识。

时间: 2024-08-23 21:22:31

Java的Socket通讯基础编程完全指南_java的相关文章

Java基于Socket实现网络编程实例详解_java

一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机. 而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的. 目前较为流行的网络编程模型是客户机/服务器(C/S)结构.即通信双方一方作为服务器等待客户提出请求并予以响应.客户则

Apache Camel的Java编程入门指南_java

 Apache Camel是一个非常实用的规则引擎库,能够用来处理来自于不同源的事件和信息.你可以在使用不同的协议比如VM,HTTP,FTP,JMS甚至是文件系统中来传递消息,并且让你的操作逻辑和传递逻辑保持分离,这能够让你更专注于消息的内容. 在这篇文章中,我将提供一个Java语言(非Groovy)的Apache Camel入门演示. 首先创建一个Maven项目的pom.xml.   <?xml version="1.0" encoding="UTF-8"?

java使用Socket类接收和发送数据_java

网络应用分为客户端和服务端两部分,而Socket类是负责处理客户端通信的Java类.通过这个类可以连接到指定IP或域名的服务器上,并且可以和服务器互相发送和接受数据.在本文及后面的数篇文章中将详细讨论Socket类的使用,内容包括Socket类基础.各式各样的连接方式.get和set方法.连接过程中的超时以及关闭网络连接等. 在本文中,我们将讨论使用Socket类的基本步骤和方法.一般网络客户端程序在连接服务程序时要进行以下三步操作. 连接服务器 发送和接收数据 关闭网络连接 一.连接服务器 在

java基于Socket做一个简单下载器_java

本文实例为大家分享了java基于Socket制作下载器的过程,及相关代码,供大家参考,具体内容如下 1.首先要建立一个服务器用来处理信息并给客户端传输文件(电脑)  我是用电脑开了一个WIFI,手机连上后使用scoket传输的  SERVERIP要根据自己实际情况更改.端口也可以随便更改0~65535,尽量选大一点  import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Bu

Java基于socket实现简易聊天室实例_java

本文实例讲述了Java基于socket实现简易聊天室的方法.分享给大家供大家参考.具体实现方法如下: chatroomdemo.java package com.socket.demo; import java.io.IOException; import java.net.DatagramSocket; public class ChatRoomDemo { /** * @param args * @throws IOException */ public static void main(S

Java中的数组基础知识学习教程_java

数字 通常情况下,当我们处理数字时,使用原始数据类型,如 byte,int,long,double 等. 示例 int i = 5000; float gpa = 13.65; byte mask = 0xaf; 然而,在开发中,我们会遇到需要使用对象而不是原始数据类型的情况.为了实现这个, Java 为每个原始数据类型提供包装类. 所有的包装类 (Integer, Long, Byte, Double, Float, Short) 是抽象类 Number 的子类. 这种包装是由编译器处理,这个

Java基于Socket的文件传输实现方法_java

本文实例讲述了Java基于Socket的文件传输实现方法.分享给大家供大家参考,具体如下: 1. Java代码如下: package sterning; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.net.Ser

JAVA多线程和并发基础面试问答(翻译)_java

Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含了不同的类和程序的单一进程.线程可以被称为轻量级进程.线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源. 2. 多线程编程的好处是什么? 在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态.多个线程共享堆内存(heap

Java开发者结合Node.js编程入门教程_java

首先, 我必须得承认,作为一个有着十多年开发经验的java开发者,我已经形成了解决绝大部分问题的固有套路,尽管它们很多时候显得笨重和繁琐. 比如说如果要读取一个文件,那应该就是初始化一个BufferedReader 实例并传入一个FileReader,这几乎是顺理成章的,我在很多自认为算得上"企业级"的项目中编写这样的代码并且很享受这个过程,可以说我就是一个对其他语言不屑一顾的java脑残粉.      如果你正在阅读这篇博文,你可能已经陷入了我多年前早就陷入的一个误区,作为一名合格的