Java笔记二十四.TCP网络编程

 TCP网络编程

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空)

从上面一节内容可以知道,利用UDP通信的两个程序是平等的,无主次之分,两个程序代码可以完全一样。但利用TCP协议进行通信的两个应用程序,是有主从之分的,一个称为服务器程序,另外一个称为客户机程序。Java中提供了ServerSocket类用于创建服务器端的socket,Socket类用于创建客户端socket。

一、APIs简介

java.net.ServerSocket

(1)功能:用于创建服务器端Socket,服务端Socket将等待网络上的客户端应用发来连接请求。

(2)构造方法

>ServerSocket() :

>ServerSocket(int port)

>ServerSocket(int port, int backlog)

>ServerSocket(int port, int backlog, InetAddress bindAddr)

用第一个构造方法创建一个ServerSocket对象,没有与任何端口号绑定,不能被直接使用,还要继续调用bind方法,才能完成其他构造方法所完成的功能。

用第二个构造方法创建一个ServerSocket对象,并与指定的端口号绑定。如果port为0,系统会应用分配一个还没有被其他网络程序所使用的端口号,作为服务器程序,端口号必须事先指定,其他客户才能根据这个端口号进行连接。

用第三个构造方法创建一个ServerSocket对象,与指定的端口号绑定并根据backlog参数指定在服务器忙时可以与之保持连接请求的等待客户数量(默认50)。

用第三个构造方法创建一个ServerSocket对象,与指定的端口号绑定、指定等待客户数量、指定本机IP。

(3)常用方法

Socket accept():服务器端等待客户端发送连接请求,并返回服务器端的Socket

void bind(SocketAddress endpoint):将服务器Socket与指定的地址(IP地址和端口号)绑定

void close():关闭该Socket

InetAddress getInetAddress():返回该服务器socket的本地地址(IP地址和端口号)

int getLocalPort():返回该服务器socket的本地端口号

java.net.Socket

(1)功能:客户端要与服务器建立连接,必须先要创建一个Socket对象。

(2)构造方法

>Socket()

>Socket(String host, int port)

>Socket(InetAddress address, int port)

>Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

>Socket(String host, int port, InetAddress localAddr, int localPort)

用第一个构造方法创建Socket对象,不与任何服务器建立连接,不能被直接使用,需要调用connect方法。

用第二或三个构造方法创建Socket对象,与指定的IP地址和端口号的服务器程序建立连接。其中,String
host为字符串格式地址,InetAddress address为InetAddress对象所包装的地址。

用第四或五个构造方法创建Socket对象,与指定的IP地址和端口号的服务器程序建立连接,并且指定了本地Socket(即客户端)所绑定的本地IP地址和端口号。

(3)常用方法

>void
connect(SocketAddress endpoint) :将该客户端socket与指定的服务器连接

>void
connect(SocketAddress endpoint, int timeout) :将该客户端socket与指定的服务器连接,并指定时限

>void
close() :关闭客户端socket

>InetAddress
getInetAddress():返回服务器程序的IP地址

>int getPort():返回服务器程序的端口号

>InputStream
getInputStream() :返回该客户端socket的一个输入流

>OutputStream
getOutputStream() :返回该客户端socket的一个输出流

二、TCP协议的Server-Client模型

1.建立Server-Client模型

(1)服务器程序创建一个ServerSocket,然后调用accept方法等待客户来连接;

(2)客户端程序创建一个Socket并请求与服务器建立连接;

(3)服务器接收客户的连接请求,并创建一个新的Socket(属于服务器)与该客户建立专线连接;

(4)刚才建立了连接的两个Socket在一个单独的线程(由服务器程序创建)上对话;

(4)服务器开始等待新的连接请求。

服务器端程序调用ServerSocket.accept方法(返回服务器的Socket)等待客户的连接请求,一旦accept接收了客户连接请求,该方法将返回一个与该客户建立了专线连接的Socket对象,而不用去创建这个服务器Socket对象。当客户端和服务器端的两个Socket建立了专线连接后,连接的一端能向另一端连续写入字节,也从另一端连续读入字节,即建立了专线连接的两个Socket是以IO流的方式进行数据交换的。Java提供了Socket.getInputStream方法返回Socket的输入流对象,Socket.getOutputStream方法返回Socket的输出流对象。只要连接的一段向该输出流对象写入了数据,连接的另一端就能从其输入流对象中读取到这些数据。

三、源码实战

1.最简单的TCP服务器程序

实现:开发一个简单的TCP服务端应用,设定其端口号,并将Windows下的telnet工具作为客户端与之通信。

ServerTCP.java

<span style="font-size:18px;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerClient {
 public static void main(String[] args)
 {

  try
  {
   //1.创建一个ServerSocket对象,用于返回服务器的Socket并指定服务器的端口号
   ServerSocket server = new ServerSocket(8000);
   Socket socket=server.accept();
   //2.获取专线Socket的输入输出流
   InputStream is = socket.getInputStream();
   OutputStream os = socket.getOutputStream();
   //3.向输出流写入字节数据
   String str = "My name is jiangdongguo.How are you!";
   os.write(str.getBytes());
   //4.从输入流读取数据并存储到指定的字节数组中
   BufferedReader br = new BufferedReader(new InputStreamReader(is));
   System.out.println(br.readLine());
//	 byte[] buf = new byte[1024];
//	 int len=is.read(buf);
//	 System.out.println(new String(buf,0,len));	//打印实际读到的数据
   socket.close();
   is.close();
   os.close();
   server.close();
  }
  catch (IOException e)
  {
   e.printStackTrace();
  }
 }
}</span>

源码分析

(1)ServerSocket server = new ServerSocket(8000); 语句作用为服务端程序创建一个在8000端口上等待连接的ServerSocket对象,当接收到一个客户的连接请求后,程序从与这个客户建立了连接的Socket对象中获得输入输出流对象,通过输出流首先向客户端发送一串字符,然后通过输入流读取客户发送过来的信息,并将这些信息存放到一个字节数组中,最后关闭所有有关的资源。

(2)由于telnet工具有输入就发送,而不等回车。如有如果服务器向将接收到的数据按一行行的格式输出。Java为我们提供了一个BufferedReader类,通过该类实现按行处理输入流。

效果演示

从下面效果可知,服务器先将数据写入Socket的输出流。当Telnet与开发的服务器连接成功后,Telent作为客户端从该socket的输入流读取数据并在终端显示。另外,我们(telnet)客户端的命令终端写入数据到socket的输出流后,服务器程序会读取socket的输入流并打印到Eclipse终端。

2.Server_Client模型应用开发

(1)服务器端

功能:在上一个程序的基础上,实现服务器程序能够接收多个客户的连接请求,并为每个客户连接创建一个单独的线程与客户进行对话。

>ServiceThread.java

子线程功能代码。每个连接的数据交换,需要放在一个循环语句中,保证两者可以不停地交换数据。客户端每向服务器发送一个字符串,服务器就将这个字符串中的所有字符反向排序后回送给客户端,直到客户端向服务器发送quit命令,结束两端的对话。

<span style="font-size:18px;">import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
//实现Runnable接口子类,完成子线程任务
public class ServiceThread implements Runnable
{
 Socket socket;

 /*构造方法,传递一个Socket对象参数*/
 public ServiceThread(Socket socket)
 {
  this.socket=socket;
 }

 /*成员方法*/
 public void run()
 {
  try
  {
   /*-----------------------------------------------------------------------------------------*/
   //1.获取Socket的输入流、输出流对象
   InputStream is =socket.getInputStream();
   OutputStream os=socket.getOutputStream();
   //2.为输入流、输出流创建两个包装类
   BufferedReader br = new BufferedReader(new InputStreamReader(is));	//输入流包装类
   DataOutputStream dos = new DataOutputStream(os);	 //输出流包装类
    /*-----------------------------------------------------------------------------------------*/
   //3.该线程不停的读取输入流中的数据并倒序
   while(true)
   {
    String str=br.readLine();	 //从输入流中读取一行字符串
    if(str.equalsIgnoreCase("quit"))
      break;
    String strReverse = (new StringBuffer(str).reverse().toString());	//将字符串倒序
    dos.writeBytes(str+"------>"+strReverse+System.getProperty("line.separator"));	//向输出流中写入字节数据
   }
   br.close();
   dos.close();
   socket.close();
  }
  catch (IOException e)
  {
   e.printStackTrace();
  }
 }
}</span>

源码分析:

(1)BufferedReader、DataOutputStream类:这两个类为IO包装类,BufferedRead类可以方便得从底层字节输入流中以整行的形式读取一个字符串;DataOutputStream类可以将一个字符串以字节数组的形式写入底层字节输出流中。

(2)System.getProperty("line.separator")用于根据不同的操作系统返回相应的换行符。

(3)在创建服务器程序Socket时需要指定其端口号(客户端才能知道哪个网络程序为服务器),然后,获取Socket的输入流、输出流用以与客户端进行数据交互。

-------------------------------------------------------------------------------------------------------------------------------------------------------

>TCPServer.java

主线程。一次accept方法调用只接受一个连接,accept方法需要方法一个循环语句中,以便接收多个客户端连接。

<span style="font-size:18px;">import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
 public static void main(String[] args)
 {
  try
  {
   ServerSocket ss = new ServerSocket(8010);//实例化一个ServerSocket对象
   while(true)
   {
    Socket socket = ss.accept();                                 //等待客户端连接请求,成功后返回服务器的socket
    new Thread(new ServiceThread(socket)).start();	 //当连接成功,为socket通信创建一个线程并启动该线程
   }
  }
  catch (IOException e)
  {
   e.printStackTrace();
  }
 }
}</span>

(2)客户端

>TCPClient.java

<span style="font-size:18px;">import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class TCPClient {
 public static void main(String[] args)
 {

  try
  {
   //1.创建客户端socket并指定服务器IP和端口号
   Socket socket = new Socket(InetAddress.getByName("192.168.1.100"),8010);
   //2.获取socket的输入流、输出流
   InputStream is = socket.getInputStream();
   OutputStream os=socket.getOutputStream();
   //3.实例化两个包装类
   BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
   DataOutputStream dos=new DataOutputStream(os);
   BufferedReader bri = new BufferedReader(new InputStreamReader(is));
   while(true)
   {
    String strKey = br.readLine();	 //从输入流读一行数据
    dos.writeBytes(strKey+System.getProperty("line.separator"));	//将键盘数据写入输出流
    if(strKey.endsWith("quit"))	 //当输入quit时,断开连接
      break;
    else
     System.out.println(bri.readLine());//从输入流读取一行数据并打印
   }
   socket.close();
   br.close();
   dos.close();
   bri.close();
  }
  catch (IOException e)
  {
   e.printStackTrace();
  }
 }
}</span>

源码分析

(1)Socket socket = new Socket(InetAddress.getByName("192.168.1.100"),8010);
语句的作用是创建客户端Socket并指定服务器的IP地址和端口号。但很多时候,为了使我们的应用程序灵活性更大,可以通过命令终端来输入服务器的IP地址和端口号:

Socket socket=null;

if(args.length<2)            //指定默认服务器IP和端口号

{

socket = new Socket(InetAddress.getByName("192.168.1.100"),8010);

}

else                                //通过命令行终端指定

{

socket=Socket((InetAddress.getByName(args[0]),Integer.parseInt(args[1]));

}

注:上述方法对服务器设置端口为一致思想。

效果演示1:

这里使用Telnet作为客户端,观察下面结果我们可以看出,在命令行运行多个"Telnet
服务器IP 服务器端口号"后,客户端程序与服务端在一个单独的线程中建立连接,实现数据交换。

效果演示2:

这里使用我们编写好的应用作为客户端,每一个客户都可以同服务器单独对话,直到客户输入quit命令后结束。其效果与telnet一致。

时间: 2024-10-22 04:09:19

Java笔记二十四.TCP网络编程的相关文章

android学习二十四(网络编程的最佳实践)

前面的博客已经讲解了HttpURLConnection和HttpClient的用法,知道了如何发起HTTP请求,以及解析服务器返回 的数据.但是可能你发现了,因为一个应用程序很多地方都可能使用网络功能,而发送HTTP请求的代码基本相同,如果每次我们都去编写一遍发送HTTP请求的代码,这显然不太好. 通常情况下我们都应该将这些通用的网络操作提取到一个公共的类里,并提供一个静态方法,当想要发起网络请求的时候只需简单地调用一下这个方法即可.比如下面的写法: package com.jack.netwo

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意

Android学习笔记二十四之ListView列表视图二

Android学习笔记二十四之ListView列表视图二 前面一篇我们介绍了常用的几种适配器的简单实现和ListView的简单使用,这一篇中,我们介绍一下ListView的优化和一些其它的问题. ListView优化方法一 在ListView中,我们最常用的就是自定义Adapter,在我们自定义Adapter中,需要实现两个比较重要的方法getCount()和getView(),前者是负责计算ListView的总Item数,后者是生成Item,有多少个Item就会调用getView()方法多少次

angular学习笔记(二十四)-$http(2)-设置http请求头

1. angular默认的请求头: 其中,Accept 和 X-Requested-With是$http自带的默认配置 2. 修改默认请求头: (1) 全局修改(整个模块) 使用$httpProvider依赖 var myApp = angular.module('MyApp',[]); myApp.config(function($httpProvider){ console.log($httpProvider.defaults.headers.common) //修改/操作$httpProv

Python基础教程(第十四章 网络编程)

本文内容全部出自<Python基础教程>第二版,在此分享自己的学习之路. ______欢迎转载:http://www.cnblogs.com/Marlowes/p/5538341.html______ Created on Marlowes 本章将会给读者展示一些例子,这些例子会使用多种Python的方法编写一个将网络(比如因特网)作为重要组成部分的程序.Python是一个很强大的网络编程工具,这么说有很多原因,首先,Python内有很多针对常见网络协议的库,在库顶部可以获得抽象层,这样就可以

第十四章 网络编程

1.网络基础 参考:http://www.cnblogs.com/Eva-J/articles/8066842.html 2.软件开发架构 C/S架构:Client与Server ,中文意思:客户端与服务器端架构,这种架构也是从用户层面(也可以是物理层面)来划分的. B/S架构:Browser与Server,中文意思:浏览器端与服务器端架构,这种架构是从用户层面来划分的.(其实B/S架构也是一种C/S架构) 3.计算机网络 1.在网络中的两个程序通过IP和PORT找到对方 IP地址是指互联网协议

Java笔记二十.深入解析I/O编程之文件访问类

深入解析I/O编程之文件访问类 转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 开始学习字节流类之前,我们来先看下与文件有关的类-File类.File类是IO包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的方法来操作文件,通过调用File类提供的各种方法,我们能够创建.删除文件.重命名文件以及判断文件的读写权限及其是否存在,设置和查询文件的最近修改时间等.在Java中,目录也被当作File使用,只是多了一些目录特有的功能---

Java笔记二十二.深入解析I/O编程之包装类

深入解析I/O编程之包装类 转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 从上节学到的节点流类我们知道,如Java中提供的FileOutputStream和FileInputStream类实现往文件中写入字节或从文件中读取字节数据.在实际应用中,我们需要往文件中写入或读取各种类型的数据,一般的做法是先将其他类型的数据转换成字节数组后写入文件或是将从文件中读取到的字节数组转换成其他类型.然而,上述方法会给我们的程序增加了代码量和带来一些困难和

Java基础学习笔记二十四 MySQL安装图解

.MYSQL的安装 1.打开下载的mysql安装文件mysql-5.5.27-win32.zip,双击解压缩,运行“setup.exe”. 2.选择安装类型,有“Typical(默认)”.“Complete(完全)”.“Custom(用户自定义)”三个选项,选择“Custom”,按“next”键继续. 3.点选“Browse”,手动指定安装目录. 4.填上安装目录,我的是“F:\Server\MySQL\MySQL Server 5.0”,也建议不要放在与操作系统同一分区,这样可以防止系统备份还