Java网络编程+多线程通信

Java网络编程+多线程通信

最近在学习Java Socket通信,把一些学到的东西贴上来。

一、Socket概念

Socket作为BSD(Berkeley Software Distribution,伯克利软件套件) UNIX的进程通信机制,通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
这里写图片描述

二、利用Socket建立网络连接的步骤**

  建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。

  套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

  1、服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

  2、客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。

  为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

  3、连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。

  而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

三、什么是TCP连接的三次握手

  第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

  第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

  第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

  握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

  理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

四、Java中的socket通信机制

Java的有联接(TCP)通信方式

Java提供的套接字分为客户端和服务器端两种:

客户端的socket
  • Socket(String host,int port):生成一个连接到某个主机内某个端口号码的套接字。
  • Socket(InetAddress host,int port):生成一个连接到某个主机地址上某个端口号码的套接字。
  • InputStream getInputStream():得到套接字的输入数据流。
  • OutputStream getOutputStream():得到套接字的输出数据流。
  • 工作完毕,使用流对象的close()方法关闭用于网络通信的输入、输出流,用Socket对象的close()方法关闭socket。
服务器端的socket
  • ServerSocket(int port):生成一个服务器套接字,并指定所使用的端口号码,在序列里等待连接的客户机的数目最大50,若端口的值为0,则使用任何可供使用的端口。
  • ServerSocket(int port,int backlog):backlog表示在序列里等待连接的客户机的数目,若数目超过backlog,则客户机的连接被拒绝。
  • InputStream getInputStream():得到套接字的输入数据流。
  • OutputStream getOutputStream():得到套接字的输出数据流。
  • Socket accept():等待接收来自客户的连接请求,服务器会等到联机为止。
  • 工作完毕,使用流对象的close()方法关闭用于网络通信的输入、输出流,用ServerSocket对象的close()方法关闭监听socket。

五、多线程通信实例

TCPServer.java

package server;

import java.awt.Font;
import java.awt.GridLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

public class TCPServer extends JFrame{
    private ServerSocket server;
    private Socket client;
    private int port;
    private static JTextField receive;
    private static JTextField send;
    private static Writer writer;
    private static BufferedReader reader;
    private static int count = 1;
    public TCPServer(int port){
        this.setTitle("Server");
        receive = new JTextField();
        send = new JTextField();
        this.setVisible(true);
        this.setBounds(400, 400, 600, 400);
        this.setLayout(new GridLayout(2,2));
        JLabel label1 = new JLabel("收到");
        label1.setFont(new Font("Dialog", 1,35));
        this.add(label1);
        this.add(receive);
        JLabel label2 = new JLabel("发送");
        label2.setFont(new Font("Dialog", 1,35));
        this.add(label2);
        this.add(send);
        validate();
        this.port = port;
        try {

            server = new ServerSocket(port);
            while(true){   //不断监听是否有客户端进程接入
                client = server.accept();
                Thread thread = new Thread(new task(client));
                thread.setName("客户端线程"+count++);
                thread.start();
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }



    static class task implements Runnable{
        Socket client;
        task(Socket client){
            this.client = client;
        }
        @Override
        public void run() {         
            try {
                handleSocket();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        private void handleSocket() throws Exception{
            try { 
                reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                while(true){
                    StringBuilder stringRead = new StringBuilder();
                    String temp;
                    int index;
                    while((temp =  reader.readLine())!= null){
                        System.out.println(temp);
                        if((index=temp.indexOf("eof"))!=-1){
                            stringRead.append(temp.substring(0, index));
                            break;
                        }
                        stringRead.append(temp);
                    }
                    System.out.println(stringRead.toString());
                    receive.setText(stringRead.toString());
                    writer = new OutputStreamWriter(client.getOutputStream());
                    if(send.getText()==""){
                        writer.write(Thread.currentThread().getName());
                    }
                    else{
                        writer.write("SendTo客户端"+Thread.currentThread().getName()+":");
                        writer.write(send.getText());
                        System.out.println("Server:send to Client:"+send.getText());
                    }
                    writer.write("eof\n");
                    writer.flush();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }       
    }

}

TCPClient.java

package client;

import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.management.ManagementFactory;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class TCPClient extends JFrame {
    private int port;
    private String host;
    private static JTextField receive;
    private static JTextField send;
    private JButton commit;
    private Socket client;
    private Writer writer;
    private BufferedReader reader;
    private String clientID;

    public TCPClient(int port,String host){
        this.setTitle("Client");
        // get name representing the running Java virtual machine.    
        String name = ManagementFactory.getRuntimeMXBean().getName();      
        // get pid    
        String clientID = name.split("@")[0];    

        this.host = host;
        this.port = port;
        this.setLayout(new GridLayout(3,1));
        receive = new JTextField();
        send = new JTextField();
        commit = new JButton("提交");
        JLabel label1 = new JLabel("收到");
        label1.setFont(new Font("Dialog", 1,35));
        JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayout(1,2));
        panel1.add(label1);
        panel1.add(receive);
        this.add(panel1);
        JLabel label2 = new JLabel("发送");
        label2.setFont(new Font("Dialog", 1,35));
        JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayout(1,2));
        panel2.add(label2);
        panel2.add(send);
        this.add(panel2);
        this.add(new JPanel().add(commit));
        this.setVisible(true);
        this.setBounds(500, 500, 600, 400);
        this.validate();        
        CreateConnection(port,host);

        commit.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                if(client.isConnected()){
                    String text = send.getText();
                    try {
                        writer.write("客户端进程"+clientID+":");
                        writer.write(text);
                        writer.write("eof\n");  
                        writer.flush();  
                        StringBuilder in  = new StringBuilder();
                        String temp;
                        int index;
                        while ((temp=reader.readLine()) != null) {  

                            if ((index = temp.indexOf("eof")) != -1) {  
                               in.append(temp.substring(0, index));  
                               break;  
                            }  
                            in.append(temp);  
                         }
                        if(in.toString()!=null){
                            System.out.println("Client:receive from Server:"+in.toString());
                            receive.setText(in.toString());
                         }
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
    }

    void CreateConnection(int port,String host){
        try {
            client = new Socket(host,port);         
            writer = new OutputStreamWriter(client.getOutputStream());
            reader = new BufferedReader(new InputStreamReader(client.getInputStream()));

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Main.java

package start;

import client.TCPClient;
import server.TCPServer;

public class Main {
    static int port;
    public static void main(String[] args){
        port = 2500;
        new TCPServer(port);
    }
}

startClient.java

package start;

import client.TCPClient;

public class startClient {
    static int port;
    static String host;
    public static void main(String[] args){
        port = 2500;
        host = "localhost";

        new TCPClient(port,host);
    }
}

功能:一个服务端同时连接多个客户端,实现并发通信,没有考虑线程安全。

我这里把客户端和服务端放在一个工程里面,在Eclipse中运行要进入到对应的main函数里。

建议把它们分别放到两个不同的工程里面。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值