关键词:
摘要:进行TCP协议网络程序的编写,关键在于ServerSocket套接字的熟练使用,TCP通信中所有的信息传输都是依托ServerSocket类的输入输出流进行的。
本文分享自华为云社区《Java利用TCP协议实现客户端与服务器通信【附通信源码】》,作者:灰小猿。
TCP协议概念
我们知道TCP是可靠而非安全的网络协议。它可以保证数据在从一端送至另一端的时候可以准确的送达,并且抵达的数据的排列顺序和送出时的顺序是相同的。因此在进行TCP协议通信的时候,我们首先应该保证客户端和服务器之间的连接通畅。
而TCP协议程序的编写,仍然是依靠套接字Socket类来实现的,并且利用TCP协议进行通信的两个程序之间是有主次之分的,即一个是服务器的程序,另一个是客户端的程序。因此两者的功能和编写上也略有不同。如下图是服务器与客户端之间进行通信的示意图:
以上就是在TCP协议中客户端与服务器建立连接的过程示意图。而在这其中起到关键作用的就是服务器端套接字ServerSocket和客户端套接字Socket。通过这两个套接字来建立服务器和客户端,从而利用其中的函数进行数据的通信。
在ServerSocket类中有很多需要注意的地方,接下来大灰狼和大家分享一下ServerSocket类的具体用法:
ServerSocket类
ServerSocket类存在于http://Java.net包中,表示服务器端的套接字,在使用时需要首先导入这个类,我们也知道ServerSocket类的主要功能就是通过指定的端口等待来自于网络中客户端的请求并且进行连接。
值得注意的是:服务器套接字一次只能与一个客户端套接字进行连接,因此如果存在多台客户端同时发送连接请求,则服务器套接字就会将请求的客户端存放到队列中去,然后从中取出一个套接字与服务器建立的套接字进行连接,但是服务器端能够容纳的客户端套接字也不是无限的,当请求连接的数量大于最大容纳量时,那么多出来的请求就会被拒接,一般来说队列的默认大小是50。
ServerSocket类的构造方法通常会抛出IOException异常,具体有以下几种形式:
- ServerSocket():创建非绑定服务器套接字
- ServerSocket(inr port):创建绑定到特定端口的服务器套接字
- ServerSocket(int port, int backlog):利用指定的backlog创建服务器套接字,并将其绑定到指定的服务器端口上,
- ServerSocket(int port, int backlog, InetAddress bindAddress):使用指定的端口,侦听backlog和要绑定到本地的IP地址创建服务器。这种情况适用于计算机上有多个网卡和多个IP地址的情况,用户可以明确的规定ServerSocket在哪块网卡或哪个IP地址上等待用户的连接请求。
以下是ServerSocket类中一些常用的方法:
了解了ServerSocket类的基本方法之后,就是如何进行客户端和服务器进行连接的问题了。
在服务器端我们可以调用ServerSocket类的accpet()方法与请求连接的客户机建立连接,这时会返回一个和客户端相连接的Socket对象,这个时候其实已经连接成功了,使用getInetAddress()方法就可以获取到进行请求的客户机的IP地址。
对于如何进行客户端和服务器端数据的通信,就要用到数据的输入流和输出流了,服务器端的Socket对象使用getOutputStream()方法获取到的输出流,将指向客户端的Socket对象使用getInputStream()方法获取到的输入流。由此就实现在服务器向客户端发送数据的一个过程,同样的道理,客户端端的Socket对象使用getOutputStream()方法获取到的输出流,将指向服务器端的Socket对象使用getInputStream()方法获取到的输入流。从而实现由客户端向服务器发送数据的过程。
注意:accpet()方法会阻塞线程的继续执行,如果在对应的接口没有收到客户端的呼叫,则程序会停留在此处,直到获取到客户端的呼叫才会继续向下执行,但是如果服务器没有收到来自客户端的呼叫请求,并且accpet()方法没有发生阻塞,那么通常情况下就是程序出了问题,一般来说可能是使用了一个已经被其他程序占用了的端口号,导致ServerSocket没有绑定成功!遇到这种情况可以尝试更换新的端口号。
了解了TCP协议的通信过程,接下来就是进行TCP通信程序的书写啦!
在网络通信中,如果只要求客户机向服务器发送信息,不要求服务器向客户端反馈信息的行为称为“单向通信”,要求客户机和服务器双方互相通信的过程称为“双向通信”,双向通信只不过是比单向通信多了一个服务器向客户端发送消息的过程,
接下来分别是服务器端和客户端程序的编写:
服务器端程序
package server_1;
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 MyTcp
private ServerSocket server; //设置服务器套接字
private Socket client; //设置客户端套接字
//连接客户端函数
void getServer()
try
server = new ServerSocket(1100); //建立服务器 端口为1100
System.out.println("服务器建立成功!正在等待连接......");
client = server.accept(); //调用服务器函数对客户端进行连接
System.out.println("客户端连接成功!ip为:" + client.getInetAddress()); //返回客户端IP
getClientMessage(); //调用信息传输和接收函数
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
void getClientMessage()
try
while (true)
InputStream is = client.getInputStream(); //获取到客户端的输入流
byte[] b = new byte[1024]; //定义字节数组
int len = is.read(b); //由于信息的传输是以二进制的形式,所以要以二进制的形式进行数据的读取
String data = new String(b, 0,len);
System.out.println("客户端发来消息:" + data);
//定义发送给客户端的输出流
OutputStream put = client.getOutputStream();
String putText = "我已经收到!欢迎你!";
put.write(putText.getBytes()); //将输出流信息以二进制的形式进行写入
catch (Exception e)
// TODO: handle exception
try
//判断客户端字节流不是空,则关闭客户端
if (server != null)
server.close();
catch (Exception e)
// TODO: handle exception
public static void main(String[] args)
// TODO Auto-generated method stub
MyTcp myTcp = new MyTcp(); //调用该类生成对象
myTcp.getServer(); //调用方法
客户端程序
package client_1;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class MyClient
private Socket client; //定义客户端套接字
//建立客户端函数
void getClient()
try
client = new Socket("127.0.0.1", 1100); //建立客户端,使用的IP为127.0.0.1,端口和服务器一样为1100
System.out.println("客户端建立成功!");
setClientMessage(); //调用客户端信息写入函数
catch (UnknownHostException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
//定义客户端信息写入函数
void setClientMessage()
try
OutputStream pt = client.getOutputStream(); //建立客户端信息输出流
String printText = "服务器你好!我是客户端!";
pt.write(printText.getBytes()); //以二进制的形式将信息进行输出
InputStream input = client.getInputStream(); //建立客户端信息输入流
byte [] b = new byte[1024]; //定义字节数组
int len = input.read(b); //读取接收的二进制信息流
String data = new String(b, 0,len);
System.out.println("收到服务器消息:" + data);
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();
try
//如果客户端信息流不为空,则说明客户端已经建立连接,关闭客户端
if (client != null)
client.close();
catch (Exception e)
// TODO: handle exception
public static void main(String[] args)
// TODO Auto-generated method stub
//生成客户端类对象
MyClient myClient = new MyClient();
myClient.getClient();
同时要注意:在客户端和服务器搭建成功之后,应该先打开服务器等待连接,再打开客户端进行连接,同样在进行关闭时,应该先关闭客户端,再关闭服务器。
以上面程序为例:
打开服务器等待客户端连接
打开客户端与服务器连接成功,并且实现双向通信:
注意:当一台机器上安装了多个网络应用程序时,很可能指定的端口已经被占用,甚至还可能遇到之前运行很好的程序突然卡住的情况,这种情况很可能是端口被别的程序占用了,这时可以运行netstat-help来活的帮助,可以使用命令netstat-an来查看该程序所使用的端口。
socket(代码片段)
...是对TCP/IP协议的封装,它的出现只是使得程序员更方便地使用TCP/IP协议栈而已。socket本身并不是协议,它是应用层与TCP/IP协议族通信的中间软件抽象层,是一组调用接口(TCP/IP网络的API函数)。更加方便程序员使用传输层TCP/IP只... 查看详情
hello/hi的简单的网络聊天程序(代码片段)
...col/InternetProtocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何在它们之间传输的标准,从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族。不同于ISO模型的七个分层,T... 查看详情
你知道http是如何使用tcp连接的吗?今天我就来告诉你!(代码片段)
1、HTTP是如何使用TCP连接的;世界上几乎所有的HTTP通信都是由TCP/IP承载的,TCP/IP是全球计算机及网络设备都在使用的一种常用的分组交换网络分层协议集。客户端应用程序可以打开一条TCP/IP连接,连接到可能运行在世界任何地方... 查看详情
tcp/ip的底层队列是如何实现的?(代码片段)
...的IO线程呢?这里就要从经典的网络C10K开始理解,服务器如何支持并发1万请求。C10K的根源在于网络的IO模型。Linux中网络处理都用同步阻塞的方式,也就是每个请求都分配一个进程或者线程,那么要支持1万并发,难道就要使用1... 查看详情
go语言网络编程(代码片段)
...络的API,它定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。电脑上运行的应用程序通常通过”套接字”向网络发出请求或者应答网络请求。Socket是应用层与TCP/IP协议族通信的中间软件抽象层。在设计模... 查看详情
使用python实现一个hello/hi的简单的网络聊天程序(代码片段)
一、TCP/IP协议通信原理 TCP/IP协议包含的范围非常的广,它是一种四层协议,包含了各种硬件、软件需求的定义。TCP/IP协议确切的说法应该是TCP/UDP/IP协议。UDP协议(UserDatagramProtocol用户数据报协议),是一种保护消息边界的... 查看详情
加深理解http请求---网络基础tcp/ip(代码片段)
...络设备要相互通信,双方就必须基于相同的方法。比如:如何探测到通信目标、由哪一方先发起通信、使用哪种语言等等好多规则。然而这种规则就是所谓的协议(protocol),你要用我就按照我协议的规则来。常用协议有:tcp,h... 查看详情
加深理解http请求---网络基础tcp/ip(代码片段)
...络设备要相互通信,双方就必须基于相同的方法。比如:如何探测到通信目标、由哪一方先发起通信、使用哪种语言等等好多规则。然而这种规则就是所谓的协议(protocol),你要用我就按照我协议的规则来。常用协议有:tcp,h... 查看详情
网络基础——tcp/ip(代码片段)
...络设备要相互通信,双方就必须基于相同的方法。比如,如何探测到通信目标、由哪一边先发起通信、使用哪种语言进行通信、怎样结束通信等规则都需要事先确定。不同的硬件、操作系统之间的通信,所有的这一切都需要一种... 查看详情
《后台开发:核心技术与应用实践》第六章(代码片段)
第6章TCP协议6.1TCP协议网络模型IOS七层网络模型五层网络模型TCP/IP分层模型应用层表示层会话层应用层应用层传输层传输层传输层网络层网络层网络层数据链路层数据链路层网络接口物理层物理层TCP/IP协议网络协议网络接口ARP网... 查看详情
网络编程(代码片段)
...所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。套接字(socket)的初使用基于TCP协议的sockettcp是基于链接的,必须先启动服务器,然后再启动客户端去链接服务器server端:1importsocket2sk=socket.socket(... 查看详情
http长连接短连接究竟是什么?(代码片段)
...。IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠地传递数据包,使得网络上接收端收到发送端所发出的所有包,并且顺序与发送顺序一致。TCP协议是可靠的、面向连接的。2.如何理解HTTP协议是无状态... 查看详情
ipc之socket的使用(代码片段)
...是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)。 Socket的使用 查看详情
unity网络通信(tcp&udp)(代码片段)
...实现UDP服务端UDP客户端TCP和UDPTCP和UDP是传输层协议,使用IP协议从一个网络传送数据包到另一个网络。把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。两者的不同是:TCP能提供有保证... 查看详情
rubysocket编程(代码片段)
...你可以轻松的对服务器进行读写。接下来就让我们来学习如何进行RubySocket编程什么是Sockets应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需... 查看详情
javase——网络编程(udp/tcp)(代码片段)
...。每台计算机都有很多的应用程序,那么在网络通信时,如何区分这些应用程序呢?如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序了。也就是应用程序的标识协议通过计算机网络可以使... 查看详情
初识socket(代码片段)
...col/InternetProtocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何再它们之间传输的标准,TCP/IP是TCP和IP协议的合称,TCP/IP协议是指因特网整个TCP/IP协议族。TCP/IP协议参考模型把所有的TCP/IP 查看详情
golangsockek编程(代码片段)
...络协议与其他计算机进行通讯网络编程中两个主要问题:如何准确定位网络上一台或多台主机(通过IP地址)找到主机后如何进行数据传输(有OSI模型和TCP/IP模型)OSI模型将网络分为7层,过于理想化,未能广泛推广TCP/IP是事实上... 查看详情