当前位置: 首页 > 后端技术 > Java

如何使用TCP-IP开发网络程序

时间:2023-04-01 15:25:31 Java

摘要:编写TCP协议网络程序的关键在于熟练使用ServerSocket套接字。TCP通信中的所有信息传输都是依靠ServerSocket类的输入输出流进行的。本文分享自华为云社区《Java利用TCP协议实现客户端与服务器通信【附通信源码】》,作者:灰小猿。TCP协议概念我们知道TCP是一种可靠但不安全的网络协议。可以保证数据从一端发送到另一端时能够准确传递,到达数据的顺序与发送时的顺序一致。因此,在进行TCP协议通信时,首先要保证客户端与服务器端的连接是畅通的。TCP协议程序的编写仍然是通过Socket类实现的,使用TCP协议进行通信的两个程序有主次之分,即一个是服务端程序,一个是客户端程序。终端程序。因此两者的功能和写法也略有不同。下图是服务端与客户端的通信示意图:上图是TCP协议中客户端与服务端建立连接的过程示意图。这里面的关键角色是服务器端套接字ServerSocket和客户端套接字Socket。server和client就是通过这两个socket建立起来的,里面的函数就是用来进行数据通信的。ServerSocket类中有很多需要注意的地方。接下来大灰狼给大家分享一下ServerSocket类的具体使用方法:使用时需要先导入这个类。我们也知道ServerSocket类的主要作用是等待网络中客户端的请求,通过指定的端口进行连接。值得注意的是,serversocket一次只能连接一个clientsocket,所以如果有多个client同时发送连接请求,serversocket会将请求的client存入队列Go,然后取从它out一个socket去和server建立的socket连接,但是server能容纳的clientsocket不是无限的,当请求的连接数大于最大容量时,那么多out的请求就会被拒绝。一般来说,队列的默认大小是50。ServerSocket类的构造函数通常会抛出一个IOException,它有以下几种形式:?ServerSocket():创建一个未绑定的服务器套接字?ServerSocket(inrport):创建一个绑定到特定端口的服务器套接字?ServerSocket(intport,intbacklog):使用指定的backlog创建一个serversocket并绑定到指定的服务器端口,?ServerSocket(intport,intbacklog,InetAddressbindAddress):使用指定的端口,监听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通信程序了!在网络通信中,如果客户端只需要向服务器发送信息,而不需要服务器向客户端反馈信息,就称为“单向通信”,要求客户端和服务器的过程相互交流称为“双向交流”。双向通信只是比单向通信多了一个服务端向客户端发送消息的过程,接下来就是编写服务端和客户端程序:服务端程序包server_1;importjava.io.BufferedReader;导入java。io.IOException;导入java.io.InputStream;导入java.io.InputStreamReader;导入java.io.OutputStream;导入java.net.ServerSocket;导入java.net.Socket;公共类MyTcp{私有ServerSocket服务器;//设置ServersocketprivateSocketclient;//设置客户端套接字//连接客户端函数voidgetServer(){try{server=newServerSocket(1100);//设置服务器端口为1100System.out.println("服务器建立成功!等待连接...");客户端=服务器。接受();//调用服务端函数连接客户端System.out.println("客户端连接成功!ip为:"+client.getInetAddress());//返回客户端IPgetClientMessage();//调用信息收发函数}catch(IOExceptione){//TODO自动生成的catch块e.printStackTrace();}}voidgetClientMessage(){try{while(true){InputStreamis=client.getInputStream();//获取客户端的输入流byte[]b=newbyte[1024];//定义字节数组intlen=is.read(b);//因为信息的传输是二进制形式,所以要以二进制形式读取数据Stringdata=newString(b,0,len);System.out.println("客户端发送信息:"+data);//定义发送给客户端的输出流OutputStreamput=client.getOutputStream();StringputText="我收到了!欢迎!";put.write(putText.getBytes());//以二进制格式写入输出流信息}}catch(Exceptione){//TODO:处理异常}try{//判断客户端字节流是否为If(server!=null){server.close();}}catch(Exceptione){//TODO:处理异常}}publicstaticvoidmain(String[]args){//TODO自动生成的方法存根MyTcpmyTcp=newMyTcp();//调用此类生成对象myTcp.getServer();//调用方法}}客户端程序包client_1;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.io.PrintWriter;importjava.net.Socket;importjava.net.UnknownHostException;publicclassMyClient{私有套接字客户端;//定义客户端端套接字//建立客户端函数voidgetClient(){try{client=newSocket("127.0.0.1",1100);//建立客户端,使用IP127.0.0.1,端口同server1100System.out.println("客户端建立成功!");设置客户端消息();//调用客户端信息写入函数}catch(UnknownHostExceptione){//TODO自动生成的catch块e.printStackTrace();}catch(IOExceptione){//TODO自动生成的catch块e.printStackTrace();}}//定义客户端信息写入函数voidsetClientMessage(){try{OutputStreampt=client.getOutputStream();//建立客户端信息输出流StringprintText="Helloserver!我是客户端!";pt.write(printText.getBytes());//以二进制格式信息输出InputStreaminput=client.getInputStream();//创建客户端信息输入流byte[]b=newbyte[1024];//定义字节数组intlen=input.read(b);//Read获取接收到的二进制信息流Stringdata=newString(b,0,len);System.out.println("收到服务器消息:"+data);}catch(IOExceptione){//TODO自动生成的catch块e.printStackTrace();}try{//如果客户端信息流不为空,说明客户端已经建立连接,关闭客户端if(client!=null){client.close();}}catch(Exceptione){//TODO:处理异常}}publicstaticvoidmain(String[]args){//TODO自动生成的方法存根//生成客户端类对象MyClientmyClient=newMyClient();myClient.getClient();}}同时请注意:客户端和服务端设置成功后,应先打开服务端等待连接,再打开客户端进行连接。同理,关闭时要先关闭客户端,再关闭服务器以上面的程序为例:打开服务器等待客户端连接打开客户端和服务器连接成功,实现二-方式通讯:注意:当一台机器上安装了多个网络应用程序时,很可能指定的端口已经被占用。你甚至可能会遇到这样的情况,之前运行良好的程序突然卡住了。在这种情况下,端口可能被另一个程序占用。这时候你可以运行netstat-help来帮助你活下去。您可以使用命令netstat-an查看程序使用的端口。点击关注,第一时间了解华为云的新鲜技术~