Java TCP/UDP网络通信编程
本文转自:http://www.cnblogs.com/cdtarena/archive/2013/04/10/3012282.html
网络应用中基本上都是TCP(Transmission Control Protocol传输控制协议)和UDP(User Datagram Protocol用户数据报协议),TCP是面向连接的通信协议,UDP是无连接的通信协议.
127.0.0.1是回路地址,用于测试,相当于localhost本机地址,没有网卡,不设DNS都可以访问.
端口地址在0~65535之间,其中0~1023之间的端口是用于一些知名的网络服务和应用,用户的普通网络应用程序应该使用1024以上的端口.
Socket连接套接字,Java分别为TCP和UDP提供了相应的类,TCP是java.net.ServerSocket(用于服务器端)和java.net.Socket(用于客户端);UDP是java.net.DatagramSocket.
1,Java编写UDP网络程序
1.1,DatagramSocket
DatagramSocket有如下构造方法: 1,DatagramSocket() :构造数据报套接字并将其绑定到本地主机上任何可用的端口。 2,DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口。 3,DatagramSocket(int port, InetAddress laddr):创建数据报套接字,将其绑定到指定的本地地址。即指定网卡发送和接收数据.
如果在创建DatagramSocket对象时,没有指定网卡的IP 地址,在发送数据时,底层驱动程序会自动选择一块网卡去发送,在接收数据时,会接收所有的网卡收到的与端口一致的数据.
发送信息时,可以不指定端口号,接收信息时,要指定端口号,因为要接收指定的数据.
发送数据使用DatagramSocket.send(DatagramPacket p)方法,接收数据使用DatagramSocket.receive(DatagramPacket p)方法.
1.2,DatagramPacket
DatagramPacket类有如下构造方法: 1,DatagramPacket(byte[] buf, int length):构造 DatagramPacket,用来接收长度为length的数据包。 2,DatagramPacket(byte[] buf, int length, InetAddress address, int port):构造数据报包,用来将长度为length的包发送到指定主机上的指定端口号。
接收数据时使用第一次构造方法,发送数据时使用第二种构造方法.
1.3,InetAddress
Java中对IP地址进行包装的类,
DatagramPacket.getAddress()可以获取发送或接收方的IP地址.DatagramPacket.getPort()可以获取发送或接收方的端口.
1.4,UDP程序例子
发送程序:
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- publicclass UdpSend {
- publicstaticvoid main(String[] args) throws Exception {
- DatagramSocket ds = new DatagramSocket();
- String str = "hello , world!";
- DatagramPacket dp = new DatagramPacket(str.getBytes(),str.length(),InetAddress.getByName("192.168.0.105"),3000);
- ds.send(dp);
- ds.close(); //关闭连接
- }
- }
接收程序:
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- publicclass UdpRecv {
- publicstaticvoid main(String[] args) throws Exception {
- DatagramSocket ds = new DatagramSocket(3000);
- byte[] buf = newbyte[1024];
- DatagramPacket dp = new DatagramPacket(buf,buf.length);
- ds.receive(dp);
- String str = new String(dp.getData(),0,dp.getLength());
- System.out.println(str);
- System.out.println("IP:" + dp.getAddress().getHostAddress() + ",PORT:" + dp.getPort());
- ds.close();
- }
- }
测试要先运行接收程序,再运行发送程序.如果接收程序没有接收到数据,则会一直阻塞,接收到数据后才会关闭程序.如果网络上没有数据发送过来,接收程序也没有阻塞,通常都是使用了一个已经被占用的端口.
2,Java编写TCP网络程序
2.1,ServerSocket
编写TCP网络服务程序,首先要用到java.net.ServerSocket类用以创建服务器Socket.它的常用构造方法有: 1,ServerSocket(int port):创建绑定到特定端口的服务器套接字。 2,ServerSocket(int port, int backlog):利用指定的backlog(服务器忙时保持连接请求的等待客户数量),创建服务器套接字并将其绑定到指定的本地端口号。 3,ServerSocket(int port, int backlog, InetAddress bindAddr):使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
2.2,Socket
客户端要与服务器建立连接,必须先创建一个Socket对象,它的常用构造方法有: 1,Socket(String host, int port):创建一个流套接字并将其连接到指定主机上的指定端口号。 2,Socket(InetAddress address, int port):创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 3,Socket(InetAddress address, int port, InetAddress localAddr, int localPort):创建一个套接字并将其连接到指定远程端口上的指定远程地址。 4,Socket(String host, int port, InetAddress localAddr, int localPort):创建一个套接字并将其连接到指定远程主机上的指定远程端口。
对于通常情况的应用,使用第1个构造方法来创建客户端的Socket对象,并与服务器建立连接,是非常简单和方便的.
服务器端程序调用ServerSocket.accept方法等待客户端的连接请求,一旦accept接收了客户端连接请求,该方法返回一个与该客户端建立了专线连接的Socket对象,不用程序去创建这个Socket对象.建立了连接的两个Socket是以IO流的方式进行数据交换的,Java提供了Socket.getInputStream返回Socket的输入流对象,Socket.getOutputStream返回Socket的输出流对象.
2.3,TCP程序例子的服务器程序:
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- publicclass TcpServer {
- publicstaticvoid main(String[] args) throws Exception {
- ServerSocket ss = new ServerSocket(8000);
- Socket s = ss.accept();
- InputStream ips = s.getInputStream();
- OutputStream ops = s.getOutputStream();
- ops.write("hello,World!".getBytes());
- byte[] buf = newbyte[1024];
- int len = ips.read(buf);
- System.out.println(new String(buf,0,len));
- ips.close();
- ops.close();
- s.close();
- ss.close();
- }
- }
在这个程序里,创建了一个在8000端口上等待连接的ServerSocket对象,当接收到一个客户的连接请求后,程序从与这个客户建立了连接的Socket对象中获得输入输出流对象,通过输出流首先向客户端发送一串字符,然后通过输入流读取客户端发送过来的信息,并将这些信息打印,然后关闭所有资源.要先运行服务器程序,然后才能运行客户端程序,当TCP服务器程序运行到Socket.accpet()方法等待客户连接时,accept方法将阻塞,一直到有客户连接请求到来,该方法才会返回,如果又没有请求到来,又没有发生阻塞,通常都是使用了一个已经被占用的端口. 我们可以使用windows提供的telnet工具在命令行窗口中测试一下服务器程序:命令如下:telnet localhost 8000 可以看到,telnet只要有输入就发送,因此我们如果想要在服务器端一次读多个字符的话,还需要进一步处理,看如下代码:
- import java.io.BufferedReader;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- publicclass TcpServer {
- publicstaticvoid main(String[] args) throws Exception {
- ServerSocket ss = new ServerSocket(8000);
- Socket s = ss.accept();
- InputStream ips = s.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(ips)); //对InputStream进行包装,增加了缓存
- OutputStream ops = s.getOutputStream();
- ops.write("hello,World!".getBytes());
- System.out.println(br.readLine());
- br.close(); //www.cdtarena.com关闭包装类,会自动关闭里面的基类
- ops.close();
- s.close();
- ss.close();
- }
- }
再次使用telnet工具可以看到,这次可以发送不止一个字符了,按回车键后发送数据到服务器端.
2.4,TCP程序例子改进后的服务器程序:
大多数情况下,服务器端都要服务多个客户端,但一次accept方法调用只接收一个连接,因此,要把accept方法放在一个循环语句中,这样就可以接收多个连接.每个连接的数据交换代码也放在一个循环中,这样才能保证两者可以不停地交换数据.
每个连接的数据交换代码必须放在独立的线程中运行,否则,这在段代码运行期间,就没法执行其他的程序代码,accept方法也得不到调用,新的连接无法进入.
下面是一个例子,客户端向服务器发送一个字符串,服务器将这个字符串中的所有字符反向排列后回送给客户端.客户端输入"quit",退出程序.
- import java.io.BufferedReader;
- import java.io.DataOutputStream;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.ServerSocket;
- import java.net.Socket;
- publicclass TcpServer {
- publicstaticvoid main(String[] args) throws Exception {
- ServerSocket ss = new ServerSocket(8000);
- while(true){
- Socket s = ss.accept();
- new Thread(new Servicer(s)).start();
- }
- }
- }
- class Servicer implements Runnable{
- Socket s;
- public Servicer(Socket s){
- this.s = s;
- }
- publicvoid run(){
- try{
- InputStream ips = s.getInputStream();
- OutputStream ops = s.getOutputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(ips));
- DataOutputStream dos = new DataOutputStream(ops);
- while(true){
- String strWord = br.readLine();
- if(strWord.equalsIgnoreCase("quit")){
- break;
- }
- String strEcho = (new StringBuffer(strWord).reverse().toString());
- dos.writeBytes(strWord + "------->" + strEcho + System.getProperty("line.separator"));
- }
- br.close();
- dos.close();
- s.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
2.5,TCP程序例子客户端程序:
- import java.io.BufferedReader;
- import java.io.DataOutputStream;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.InetAddress;
- import java.net.Socket;
- publicclass TcpClient {
- publicstaticvoid main(String[] args) throws Exception{
- if(args.length < 2){
- System.out.println("Usage:java TcpClient ServerIP ServerPort");
- return ;
- }
- Socket s = new Socket(InetAddress.getByName(args[0]),Integer.parseInt(args[1]));
- InputStream ips = s.getInputStream();
- OutputStream ops = s.getOutputStream();
- BufferedReader brKey = new BufferedReader(new InputStreamReader(System.in));
- DataOutputStream dos = new DataOutputStream(ops);
- BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
- while(true){
- String strWord = brKey.readLine();
- dos.writeBytes(strWord + System.getProperty("line.separator"));
- if("quit".equalsIgnoreCase(strWord)){
- break;
- }else{
- System.out.println(brNet.readLine());
- }
- }
- dos.close();
- brNet.close();
- brKey.close();
- s.close();
- }
- }
先运行服务器程序,再在命令行使用java TcpClient 192.168.0.3 8000,这样就启动了客户端程序.我们可以启动多个客户端程序.
我们可以利用netstat工具来查看已经被使用的端口
Java TCP/UDP网络通信编程的更多相关文章
- Java中的TCP/UDP网络通信编程
127.0.0.1是回路地址,用于测试,相当于localhost本机地址,没有网卡,不设DNS都可以访问. 端口地址在0~65535之间,其中0~1023之间的端口是用于一些知名的网络服务和应用,用户 ...
- 三十天学不会TCP,UDP/IP编程--MAC地址和数据链路层
这篇文章主要是来做(da)推(guang)介(gao)的!由于这两年接触到了比较多的这方面的知识,不想忘了,我决定把他们记录下来,所以决定在GitBook用半年时间上面写下来,这是目前写的一节,后面会 ...
- 一个项目看java TCP/IP Socket编程
前一段时间刚做了个java程序和网络上多台机器的c程序通讯的项目,遵循的是TCP/IP协议,用到了java的Socket编程.网络通讯是java的强项,用TCP/IP协议可以方便的和网络上的其他程序互 ...
- TCP UDP基本编程(一)
tcp udp均可以用来网络通信,在使用之前建议先搜索一下相关网络连接的基本知识,可以更好的理解和使用,tcp建议看下如下文章:https://blog.csdn.net/chuangsun/arti ...
- java tcp ip网络编程(二) 套接字的基本使用
##基本套接字的使用 linux系统把网络io抽象成socket,对网络的编程就是对socket的编程. java把套接字抽象成类似的类 InetAddress SocketAddress 识别jav ...
- Go语言TCP/UDP Socket编程
1. TCP编程 TCPClient // TCPClient project main.go package main import ( "fmt" "net" ...
- tcp/udp socket编程异同
一.TCP与UDP的区别 基于连接与无连接 对系统资源的要求(TCP较多,UDP少) UDP程序结构较简单 流模式与数据报模式 TCP保证数据正确性,UDP可能丢包 TCP保证数据顺序,UDP不保证 ...
- [Java] Tcp/udp 简单通信
本文转自 我自己的博客guozeyiblog.cn 欢迎来訪 效果图: //UDP通信 import java.awt.*; import java.awt.event.ActionEvent; i ...
- TCP/UDP网络编程的基础知识与基本示例(windows和Linux)
一.TCP编程的一般步骤 服务器端: 1.创建一个socket,用函数socket() 2.绑定IP地址.端口等信息到socket上,用函数bind() 3.开启监听,用函数listen() 4.接收 ...
随机推荐
- Monkey源代码分析之执行流程
在<MonkeyRunner源代码分析之与Android设备通讯方式>中.我们谈及到MonkeyRunner控制目标android设备有多种方法.当中之中的一个就是在目标机器启动一个mon ...
- HttpClient4的使用,模拟浏览器登陆新浪微博,发表微博和文字+图片微博
HttpClient4,最原始的需求就是使用其来模拟浏览器想服务器发起http请求,当然,他的功能不止于此,但是我需要的就是这个功能而已,jdk也有其自带的类似的api:UrlConnection,效 ...
- Linux虚拟文件系统VFS解决
参考<Linux内核设计与实现> 虚拟文件系统(VFS)它是linux核心和详细I/O一个普通的访问接口之间的包装设备,通过这层界面,linux内核能够以同一的方式訪问各种I/O设备. 虚 ...
- codeforces55D数位dp
codeforces55D 查询给定区间内的beautiful number. 一个数字是beautiful number当且仅当能被自己的各个数字不为0的位整除. 这个dp的状态还是挺难想的.一个 ...
- UVALive 3890 Most Distant Point from the Sea(凸包最大内接园)
一个n个点的凸多边形,求多边形中离多边形边界最远的距离.实际上就是求凸包最大内接圆的半径. 利用半平面交求解,每次二分枚举半径d,然后将凸包每条边所代表的半平面沿其垂直单位法向量平移d,看所有平移后的 ...
- linux设备驱动程序第四部分:从如何定位oops对代码的调试方法,驱动线
在一个我们谈到了如何编写一个简单的字符设备驱动程序,我们不是神,编写肯定会失败的代码,在这个过程中,我们需要继续写代码调试.在普通c应用.我们经常使用printf输出信息.或者使用gdb要调试程序,然 ...
- oracle分区表运行计划
分区表有非常多优点,以大化小,一小化了,加上并行的使用,在loap中能往往能提高几十倍甚至几百倍的效果. 当然表设计得不好也会适得其反.效果比普通表跟糟糕. 为了更好的使用分区表,这里看一下分区表的运 ...
- Windows Phone 如果你把Pivot控件当成主页面,那么这篇文章你值得看。
原文:Windows Phone 如果你把Pivot控件当成主页面,那么这篇文章你值得看. 现在很多App都用到了Pivot视图 来当作 整个App主页面.如果你的Pivot视图主页面承载了大量数据的 ...
- 间隔DP基础 POJ2955——Brackets
取血怒.first blood,第一区间DP,这样第一次没有以某种方式在不知不觉中下降~~~ 题目尽管是鸟语.但还是非常赤裸裸的告诉我们要求最大的括号匹配数.DP走起~ dp[i][j]表示区间[i, ...
- Oracle Hints详细解释
特别介绍给大家Oracle Hints之前,让我们知道下Oracle Hints什么,然后好Oracle Hints,我们希望实际.基于成本的优化器是很聪明,在大多数情况下,将选择正确的优化,减少DB ...