JAVA-hello/hi的简单的网络聊天程序

 

使用Tcp协议的Socket编程主要用到两个类,Socket和ServerSocket。ServerSocket本身也是一个Socket,只是它同时包含了一些额外的服务器终端的功能,比如监听端口,等待客户端Socket前来建立连接等。通过accept方法一旦和客户端建立起连接,就会返回一个普通的Socket和客户端Socket进行对等的通信。

本文的Demo实现的功能很简单,用户输入消息,发送给服务器,服务器原封不动返回给客户端。原理是:启动一个服务器线程和两个客户端线程。服务器线程监听2000端口,等待客户端进程的连接。客户端线程包括一个发送线程和一个接收线程,发送线程连接服务器的2000端口,将用户输入的消息发送给服务器线程,接收线程监听2001端口,等待服务器返回的数据。服务器通过2000端口收到客户端发来的数据后,将数据原封不动发送到客户端的2001端口,完成通信。

所谓socket 通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过”套接字”向网络发出请求或者应答网络请求。

以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

重要的Socket API

java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。

Accept方法用于产生”阻塞”,直到接受到一个连接,并且返回一个客户端的Socket对象实例。”阻塞”是一个术语,它使程序运行暂时”停留”在这个地方,直到一个会话产生,然后程序继续;通常”阻塞”是由循环产生的。
getInputStream方法获得网络连接输入,同时返回一个InputStream对象实例。
getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。
注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。

TCP 编程

服务器端套路

1.创建ServerSocket对象,绑定监听端口。
2.通过accept()方法监听客户端请求。
3.连接建立后,通过输入流读取客户端发送的请求信息。
4.通过输出流向客户端发送响应信息。
5.关闭响应的资源。

客户端套路

扫描二维码关注公众号,回复: 8115219 查看本文章

1.创建Socket对象,指明需要连接的服务器的地址和端口号。
2.连接建立后,通过输出流向服务器发送请求信息。
3.通过输入流获取服务器响应的信息。
4.关闭相应资源。

多线程实现服务器与多客户端之间通信步骤

1.服务器端创建ServerSocket,循环调用accept()等待客户端连接。
2.客户端创建一个socket并请求和服务器端连接。
3.服务器端接受客户端请求,创建socket与该客户建立专线连接。
4.建立连接的两个socket在一个单独的线程上对话。
5.服务器端继续等待新的连接。

首先是服务端代码:

package ChatTwoPackage;
  
import java.io.*;
import java.net.*;
  
public class ChatTwoServer {
  
  public ChatTwoServer( int port,String name) throws IOException
  {
  ServerSocket server= new ServerSocket(port); //创建seversocket对象,提供tcp连接服务。指定端口port,等待tcp连接。
  System.out.print( "正在等待连接,请勿操作!" );
  Socket client=server.accept(); //创建socket对象,它等待接收客户端的连接。
  new ChatTwoClient(name,client); //实现图形界面。
  server.close();
  }
  
  public static void main(String[] args) throws IOException {
  new ChatTwoServer( 2001 , "SQ" );
  
  }
  
}
然后是客户端的代码:
package ChatTwoPackage;
  
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;
  
public class ChatTwoClient extends JFrame implements ActionListener {
  private String name;
  private JTextArea text_re;
  private JTextField text_se;
  private PrintWriter cout;
  private JButton buttons[];
  public ChatTwoClient(String name,Socket socket) throws IOException
  {
  super ( "我:" +name+InetAddress.getLocalHost().getHostAddress()+ ":" +socket.getLocalPort());
  this .setBounds( 320 , 240 , 400 , 240 );
  this .text_re= new JTextArea();
  this .text_re.setEditable( false );
  this .getContentPane().add( new JScrollPane( this .text_re));
  
  JToolBar toolBar= new JToolBar();
  this .getContentPane().add(toolBar, "South" );
  toolBar.add( this .text_se= new JTextField( 30 ));
  buttons= new JButton[ 2 ];
  buttons[ 0 ]= new JButton( "发送" );
  buttons[ 1 ]= new JButton( "下线" );
  toolBar.add(buttons[ 0 ]);
  toolBar.add(buttons[ 1 ]);
  buttons[ 0 ].addActionListener( this );
  buttons[ 1 ].addActionListener( this ); //给按钮添加事件监听,委托当前对象处理
  this .setVisible( true );
  this .name=name;
  this .cout= new PrintWriter(socket.getOutputStream(), true ); //获得socket输出流
  this .cout.println(name);
  BufferedReader br= new BufferedReader( new InputStreamReader(socket.getInputStream())); //将socket的字节输入流转换为字符流,默认GBK字符集,再创建缓冲字符输入流
         String line= "连接" +br.readLine()+ "成功" ;
         while (line!= null &&!line.endsWith( "bye" ))
  {
   text_re.append(line+ "\r\n" );
   line=br.readLine();
  } //读取对方发送的内容并显示,直到内容为为空或对方下线
  br.close();
  this .cout.close();
  socket.close();
  buttons[ 0 ].setEnabled( false );
  buttons[ 1 ].setEnabled( false );
  }
  public ChatTwoClient(String name,String host, int port) throws IOException
  {
  this (name, new Socket(host,port)); //调用另一个构造方法
  }
  public void actionPerformed(ActionEvent ev)
  {
  if (ev.getActionCommand().equals( "发送" ))
  {
   this .cout.println(name+ ":" +text_se.getText());
   text_re.append( "我:" +text_se.getText()+ "\n" );
   text_se.setText( "" );
  } //按下发送按钮后,将内容发出,并更新自己聊天框的内容
  if (ev.getActionCommand().equals( "下线" ))
  {
   text_re.append( "你已下线\n" );
   this .cout.println(name+ "离线\n" + "bye\n" );
   buttons[ 0 ].setEnabled( false );
   buttons[ 1 ].setEnabled( false );
  } //下线按钮按下后,发送bye作为下线标记
  }
  
  
  public static void main(String[] args) throws IOException {
  new ChatTwoClient( "mxl" , "127.0.0.1" , 2001 ); //ip地址和端口
  
  }
  
}
运行效果:
 
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/xqqu/p/12005773.html