就是一个简单的客户端发消息,服务器端接收的单向过程
服务器代码为
import java.net.*;
import java.io.*;public class SP {
private Socket s;
public DataInputStream dis;
public SP() throws Exception {
ServerSocket ss=new ServerSocket(6618);
//while(true) {
 s = ss.accept();
    dis = new DataInputStream(s.getInputStream());  
// }

}
public void CClose() throws Exception {
s.close();
dis.close();

}
}import javax.swing.*;
import java.awt.*;public class SUI extends JFrame  {

private JTextArea JTA;
private Container container;
public SUI () {
super("进程通信");
try {

this.setLayout(new FlowLayout());
container = this.getContentPane();
JTA = new JTextArea();
JTA.setRows(6);
JTA.setColumns(30);
this.setLocation(234, 40);
this.setSize(400,240);
container.add(JTA);
this.setVisible(true);
while (true) {
SP C = new SP();

JTA.setText(C.dis.readUTF());
C.CClose();
}

}catch(Exception E){}
}

客户端代码为:import java.net.*;
import java.io.*;public class TCPClient {
private Socket s;
public  DataOutputStream dos;
public TCPClient() throws Exception {

 s=new Socket("127.0.0.1",6618);
OutputStream os = s.getOutputStream();
 dos=new DataOutputStream(os);
}
public void CClose() throws Exception {
dos.flush();
dos.close();
s.close();
}}import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;public class CUI extends JFrame implements ActionListener  {
private JTextArea JTA;  private JButton JB1,JB2;
private JLabel JL;
private Container container;

public CUI () {
super("进程通信");
this.setLayout(new FlowLayout());
container = this.getContentPane();
JTA = new JTextArea();
JTA.setRows(6);
JTA.setColumns(30);
JL = new JLabel("客户端");
JB1 = new JButton("发送");
JB2 = new JButton("取消");
container.add(JL);
container.add(JTA);
container.add(JB1);
container.add(JB2);
JB1.addActionListener(this);
JB2.addActionListener(this);
this.setLocation(234, 40);
this.setSize(400,240);
this.setVisible(true); }

 public void actionPerformed(ActionEvent e){ 


try {
TCPClient C = new TCPClient();

if(e.getSource()==JB1) {
if(JTA.getText()==null) {
JOptionPane.showMessageDialog(new JFrame(),
                    "发送内容不能为空!",
                    "进程通信",
                    JOptionPane.INFORMATION_MESSAGE
                    );
}
else {
C.dos.writeUTF(JTA.getText());
C.CClose();
}
}
else if(e.getSource()==JB2) {
JTA.setText(null);
}
}catch (Exception a){}

}
public static void main(String[] args) throws Exception{

new CUI();

}

}
代码有很多规范问题,现在这不是讨论的重点(初学)
我的问题是:
1.为什么每次运行程序只能发送一次消息,后面即使更改发送内容,服务器端仍没反应?
2.每次运行完后,关闭程序,然后再打开都需更换端口,不然的话程序没任何反应?
3.有人可能发现了我的服务器端没有循环监听(将死循环注释掉了),因为如果加上的话,程序同样没反应(一次都不能发送),哪出问题了?希望你能耐心看完,指点一二,不胜感激啊

解决方案 »

  1.   

    我看了一下,感觉是在创建ServerSocket时前一个没有关闭,后一个又开始创建发现端口被占用,从而产生异常,导致只能接受一组数据
    你在SP中添加关闭ServerSocket的代码就行了\import java.net.*;
    import java.io.*;public class SP 
    {
    private Socket s;
    public DataInputStream dis;
    ServerSocket ss;
    public SP() throws Exception 
    {
    ss=new ServerSocket(6618);
    //while(true) {
    s = ss.accept();
    dis = new DataInputStream(s.getInputStream());
    // }
    }

    public void CClose() throws Exception 
    {
    s.close();
    dis.close();
    ss.close(); //在这里把ServerSocket也关了
    }
    }
      

  2.   

    不是socket关闭错误的问题.
    第一个问题:
       服务端ServerSocket创建你放在了public SP()构造方法里,而且是局部变量引用,所以当public SP()执行完毕,也就是服务器创建完毕之后,这个ServerSocket相对这个服务器对象来说已经消失了,因为你没有用一个全局变量引用它,相对内存来说,ServerSocket还没有消失,而且还没有关闭,这时候客户端再次发消息时,客户端会用一个新的socket去与ServerSocket建立连接,ServerSocket接收到连接还会分配出一个新的socket,楼主并未用新的socket读取信息,所以表象是只能发送读取一次
    第二个问题:
       肯定是端口被占用的问题,这一定是ServerSocket未关闭造成的,楼主仔细检查程序的推出代码是否正确,最简单的 System.exit(-1);
    第三个问题:
       while(true),死循环啊 ,除非内部代码抛异常,否则楼主的代码是不会退出循环的.
       while(true)循环中,服务器一直在做接受连接的事情,所以我想楼主的情形是:客户端 发送 按钮点击无数次,都没反应,而且还没任何异常,解决方法是如果楼主不考虑多线程,就把循环去掉.总结;
       楼主的主要问题:
         1. 对整个交互过程,情景还不是太清楚.
         2. 在代码实现上,代码结构混乱,主要还是上面原因造成的.
         3. 对程序控制,比如说循环可能理解不够充分.  解决方案 你先自己想吧
       
       
      

  3.   

    试了一下,主要有2个问题:
    1.JFame调用setVisible之后,还要调用setDefaultCloseOperation(3),不然的话,你点了窗体的关闭后,只是把窗体隐藏了,进程还没有退出,所以,再启动的话,就得换一个端口才行。
    2.在SUI中的while中SP C = new SP();这个肯定不行,因为new SP的时候要创建ServerSocket。
    应该在循环开始前创建ServerSocket,在循环中accept连接并读写数据。
    SUI代码片段SP C = new SP();
    while (true) {
        C.listen();
        JTA.setText(C.dis.readUTF());
        C.CClose();
    }SP代码片段public SP() throws Exception {
        ss = new ServerSocket(6618);
        }

    public void listen() throws IOException{
        s = ss.accept();
        dis = new DataInputStream(s.getInputStream());
    }
      

  4.   


    服务器接收端,本就该用while(true)循环读取客户端的数据,
    通用的端口接收数据的做法就是这么实现的。
    不知道你为什么把while(true)循环给注释掉了?!这样的话只能读取一次!另外,退出循环的通用做法是,当客户端发送特殊信息,比如"quit","exit"的时候,
    在while(true)循环内判断客户端发送的内容,再退出循环,关闭端口!有时间看看经典的JAVA教程。
      

  5.   


    是的,呵呵.但楼主的while(true)是用来不断接受客户端连接并分配与之对应的socket用的,这种情景下就需要给每个客户端分配一个线程独立去通信,
      

  6.   

    楼主问题的本质是 ServerSocket 应该用全局变量引用,而非局部变量
    5楼的是正确的
      

  7.   

    别误解,当有新的客户端要连接的话,当然要创建新的线程来处理,
    while(true)循环是在某一个线程内不断接受某一个客户端的信息,
    这并不矛盾。
    搂主应该把服务器端代码分为两个模块
    1.接收连接请求,建立连接,创建线程。
    2.在这个启动的线程内循环读取客户端的信息。
      

  8.   

    那我把全部修改的代码贴出来参考一下吧,至少我这里是可以运行的import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.net.*;
    import java.io.*;public class CUI extends JFrame implements ActionListener 
    {
    private JTextArea JTA;
    private JButton JB1,JB2;
    private JLabel JL;
    private Container container;

    public CUI () throws Exception 
    {
    super("进程通信");
    this.setLayout(new FlowLayout());
    container = this.getContentPane();
    JTA = new JTextArea();
    JTA.setRows(6);
    JTA.setColumns(30);
    JL = new JLabel("客户端");
    JB1 = new JButton("发送");
    JB2 = new JButton("取消");
    container.add(JL);
    container.add(JTA);
    container.add(JB1);
    container.add(JB2);
    JB1.addActionListener(this);
    JB2.addActionListener(this);
    this.setLocation(234, 40);
    this.setSize(400,240);
    this.setVisible(true);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    } public void actionPerformed(ActionEvent e)
    {
    try 
    {
    TCPClient C = new TCPClient();
    if(e.getSource()==JB1) 
    {
    if(JTA.getText()==null) 
    {
    JOptionPane.showMessageDialog(new JFrame(),"发送内容不能为空!","进程通信",JOptionPane.INFORMATION_MESSAGE);
    }
    else 
    {
    C.dos.writeUTF(JTA.getText());
    C.CClose();
    }
    }
    else if(e.getSource()==JB2) 
    {
    JTA.setText(null);
    }
    }
    catch (Exception a)
    {
    }
    }

    public static void main(String[] args) throws Exception
    {
    new CUI();
    }
    }
    import javax.swing.*;
    import java.awt.*;public class SUI extends JFrame 
    {
    private JTextArea JTA;
    private Container container;

    public SUI () 
    {
    super("进程通信");
    try 
    {
    this.setLayout(new FlowLayout());
    container = this.getContentPane();
    JTA = new JTextArea();
    JTA.setRows(6);
    JTA.setColumns(30);
    this.setLocation(234, 40);
    this.setSize(400,240);
    container.add(JTA);
    this.setVisible(true);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    while (true) 
    {
    SP C = new SP();
    JTA.setText(C.dis.readUTF());
    C.CClose();
    }
    }
    catch(Exception E)
    {
    }
    }

    public static void main(String[] args)
    {
    new SUI();
    }
    }
    import java.net.*;
    import java.io.*;public class SP 
    {
    private Socket s;
    public DataInputStream dis;
    ServerSocket ss;
    public SP() throws Exception 
    {
    ss=new ServerSocket(6618);
    //while(true) {
    s = ss.accept();
    dis = new DataInputStream(s.getInputStream());
    // }
    }

    public void CClose() throws Exception 
    {
    s.close();
    dis.close();
    ss.close(); //在这里把ServerSocket也关了
    }
    }
    import java.net.*;
    import java.io.*;public class TCPClient 
    {
    private Socket s;
    public DataOutputStream dos; public TCPClient() throws Exception 
    {
    s=new Socket("127.0.0.1",6618);
    OutputStream os = s.getOutputStream();
    dos=new DataOutputStream(os);
    }

    public void CClose() throws Exception 
    {
    dos.flush();
    dos.close();
    s.close();
    }
    }运行时先运行SUI,再运行CUI,关闭时同时关闭。这样应该不会有问题了吧
      

  9.   

    把CUI再稍稍改一下,上面的程序在CUI中按取消后会出现无法发送数据的情况,那是因为建立了一个多余的Socket,把TCPClient C = new TCPClient(); 改到if语句里面就行了import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.net.*;
    import java.io.*;public class CUI extends JFrame implements ActionListener 
    {
    private JTextArea JTA;
    private JButton JB1,JB2;
    private JLabel JL;
    private Container container;

    public CUI () throws Exception 
    {
    super("进程通信");
    this.setLayout(new FlowLayout());
    container = this.getContentPane();
    JTA = new JTextArea();
    JTA.setRows(6);
    JTA.setColumns(30);
    JL = new JLabel("客户端");
    JB1 = new JButton("发送");
    JB2 = new JButton("取消");
    container.add(JL);
    container.add(JTA);
    container.add(JB1);
    container.add(JB2);
    JB1.addActionListener(this);
    JB2.addActionListener(this);
    this.setLocation(234, 40);
    this.setSize(400,240);
    this.setVisible(true);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    } public void actionPerformed(ActionEvent e)
    {
    try 
    {
    if(e.getSource()==JB1) 
    {
    TCPClient C = new TCPClient();
    if(JTA.getText()==null) 
    {
    JOptionPane.showMessageDialog(new JFrame(),"发送内容不能为空!","进程通信",JOptionPane.INFORMATION_MESSAGE);
    }
    else 
    {
    C.dos.writeUTF(JTA.getText());
    C.CClose();
    }
    }
    else if(e.getSource()==JB2) 
    {
    JTA.setText(null);
    }
    }
    catch (Exception a)
    {
    }
    }

    public static void main(String[] args) throws Exception
    {
    new CUI();
    }
    }
      

  10.   

    <Head first Java>是本好书,里面就有个详细的socket编程例子。