通信基础——实现服务器与客户端的交流
大家好~~~好久不见~~~感谢大家一直以来对我的博客的关注与支持,最近比较忙~~技术博客写得少少的~~对不起一直关注我的朋友们~~现在~~我要写新东西啦~
是不是很期待呢,好的~~下面我将对我在通信方面的成果做一个展示:
服务器端:
下面是做服务器端的一点心得体会:
一、制作服务器端的三大步骤:
1、 在指定端口上创建一个java.net.ServerSocket对象;
2、 当服务器创建成功后,就像的的手机开机后,进入待机状态一样,你也要让服务器进入等待状态,当然是其他客户机来连接它;
3、 从Socket连结对象上调用方法得到输入输出流;
4、 如果你使用过输入/输出流对象,也许不用看这步了;但我还是要提醒下,现在就可以通
信了:从输入流中读取数据,向输出流中写入数据,读到的,即是客户机发来的;
二、避免阻塞现象产生的方法是使用线程,使用线程在每次创建一个连接的时候,不然如果服务器不接收到消息就不会进入下一步,一直阻塞在那里;如果使用界面,建立连接时也需要使用线程;
三、在读取客户端发来的文本信息时,readline()读取中文不会出现乱码,如果按本文中的方法一个字节一个字节地读写就会出现乱码,因为中文占两个字节,不过不推荐使用readline,因为它只能读取文本格式的。
package Connect;
publicclass Connect2 {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) throws Exception {
// TODO Auto-generated method stub
Serverjframe serverjframe = new Serverjframe();
serverjframe.Serverjfr();
}
}
package Connect;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class JButtonListener implements ActionListener {
private JTextArea jTextArea;
private String str;
private JTextField jTextField;
private JButton jButton;
private JTextField jTextFieldmsg;
public JButtonListener(JTextField jTextField,JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg){
this.jTextField = jTextField;
this.jTextArea = jTextArea;
this.jButton = jButton;
this.jTextFieldmsg = jTextFieldmsg;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
str = jTextField.getText();
int Str = Integer.parseInt(str);
System.out.println(str);
JframeThread jfThread = new JframeThread(Str,jTextArea,jButton,jTextFieldmsg);
jfThread.start();
}
}
package Connect;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
publicclass JframeThread extends Thread{
private JButton jButton;
private JTextField jTextFieldmsg;
private JTextArea jTextArea;
privateintStr;
public JframeThread(int Str,JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg) {
// TODO Auto-generated constructor stub
this.Str = Str;
this.jTextArea = jTextArea;
this.jTextFieldmsg = jTextFieldmsg;
this.jButton = jButton;
}
publicvoid run(){
Netconnect netconnect = new Netconnect(jTextArea,jButton,jTextFieldmsg);
netconnect.setUpServer(Str);
}
}
package Connect;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class JbuttonmsgListener implements ActionListener{
private ServerThread serverThread;
private JTextField jTextField;
private JTextArea jTextArea;
public JbuttonmsgListener(JTextField jTextField,JTextArea jTextArea,ServerThread serverThread){
this.jTextField = jTextField;
this.jTextArea = jTextArea;
this.serverThread = serverThread;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
try {
String string ="服务器说:"+jTextField.getText()+"\r\n";
serverThread.sendMsg2Me(string);
jTextArea.append(jTextField.getText());
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
package Connect;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Netconnect {
private JTextArea jTextArea;
private JButton jButton;
private JTextField jTextFieldmsg;
public Netconnect(JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg){
this.jTextArea = jTextArea;
this.jButton = jButton;
this.jTextFieldmsg = jTextFieldmsg;
}
public void setUpServer(int port) {
try {
ServerSocket server=new ServerSocket(port);
System.out.println("服务器创建成功!"+port);
while(true)
{
Socket client = server.accept();
System.out.println("已经启动一个线程,去处理它呵呵");
ClientAlreadyConnect pClient = new ClientAlreadyConnect();
pClient = pClient.createOne();
System.out.println("用户:"+pClient.getName()+"已经被创建;");
ServerThread st = new ServerThread(client,jTextArea,jButton,jTextFieldmsg,pClient);
st.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package Connect;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Serverjframe extends javax.swing.JFrame {
public void Serverjfr(){
this.setSize(400, 400);
this.setTitle("呵呵服务器");
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
this.setLayout(new BorderLayout());
//北部创建服务器
JButton jButton = new JButton("端口号:");
JTextField jTextField = new JTextField("8090");
jTextField.setPreferredSize(new Dimension(100,30));
JPanel northjPanel = new JPanel();
northjPanel.add(jButton);
northjPanel.add(jTextField);
this.add(northjPanel,BorderLayout.NORTH);
//中部输入框:
JPanel jPanel = new JPanel();//面板
JButton jButtonmsg = new JButton("发布消息");
JTextField jTextFieldcenter = new JTextField();
jTextFieldcenter.setPreferredSize(new Dimension(280,30));
jTextFieldcenter.setHorizontalAlignment(JTextField.LEFT);
jPanel.add(jButtonmsg);
jPanel.add(jTextFieldcenter);
this.add(jPanel,BorderLayout.CENTER);
//南部显示框
JPanel southjPanel = new JPanel();
JTextArea jTextAreasouth = new JTextArea("");
jTextAreasouth.setPreferredSize(new Dimension(350,260));
southjPanel.add(jTextAreasouth);
this.add(southjPanel,BorderLayout.SOUTH);
this.setVisible(true);
JButtonListener jButtonListener = new JButtonListener(jTextField,jTextAreasouth,jButtonmsg,jTextFieldcenter);
jButton.addActionListener(jButtonListener);
}
}
package Connect;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ServerThread extends Thread{
private Socket client;//线程对象要处理的连结变量
private OutputStream out;
private JTextArea jTextArea;
private JButton jButton;
private JTextField jTextFieldmsg;
private ClientAlreadyConnect pClient;
public ServerThread(JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg,ClientAlreadyConnect pClient){
this.jTextArea =jTextArea;
this.jButton = jButton;
this.jTextFieldmsg = jTextFieldmsg;
this.pClient = pClient;
}
public ServerThread(Socket sc,JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg,ClientAlreadyConnect pClient){
this.client = sc;
this.jTextArea = jTextArea;
this.jButton = jButton;
this.jTextFieldmsg = jTextFieldmsg;
this.pClient = pClient;
}
public void sendMsg2Me(String msg) throws Exception{
byte[] data = msg.getBytes();
out.write(data);
out.flush();
}
public void run(){
//在线程run中调用处理节点的方法
process(this.client);
}
private void process(Socket client) {
try{
JbuttonmsgListener jbmsgListener = new JbuttonmsgListener(jTextFieldmsg,jTextArea,this);
jButton.addActionListener(jbmsgListener);
InputStream ins = client.getInputStream();
out = client.getOutputStream();
String string = " Hello,欢迎来的香煎马鲛鱼的服务器\r\n";
this.sendMsg2Me(string);
//调用读取字符串的方法,从输入流读取一个字符串
String insputS = readString(ins);
while(!insputS.equals("bye")){
string = "(客户端"+pClient.getName()+"消息)";
this.sendMsg2Me(string);
jTextArea.append(string);
insputS = readString(ins);
String string2 = null;
//System.out.println(string2);
//this.sendMsg2Me(insputS);
}
string = "大爷走好~~以后常来玩啊~~\r\n";
this.sendMsg2Me(string);
client.close();
insputS = readString(ins);
}
catch(Exception e){
}
}
private String readString(InputStream ins) throws Exception{
StringBuffer stb = new StringBuffer();
int i = ins.read();
char c = 0;
while(c!=13){
c = (char)i;
stb.append(c);
i = ins.read();
}
//将读到的字节组转为字符串,并调用trim去掉尾部的空格
String inputS =stb.toString().trim();
jTextArea.append(inputS);
return inputS;
}
}
//将发送信息的代码包装在一个方法中
package Connect;
import java.util.List;
import java.util.ArrayList;
public class Configstatic {
public static List<ClientAlreadyConnect> allClient = new ArrayList<ClientAlreadyConnect>();
}
package Connect;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ServerThread extends Thread{
private Socket client;//线程对象要处理的连结变量
private OutputStream out;
private JTextArea jTextArea;
private JButton jButton;
private JTextField jTextFieldmsg;
private ClientAlreadyConnect pClient;
public ServerThread(JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg,ClientAlreadyConnect pClient){
this.jTextArea =jTextArea;
this.jButton = jButton;
this.jTextFieldmsg = jTextFieldmsg;
this.pClient = pClient;
}
public ServerThread(Socket sc,JTextArea jTextArea,JButton jButton,JTextField jTextFieldmsg,ClientAlreadyConnect pClient){
this.client = sc;
this.jTextArea = jTextArea;
this.jButton = jButton;
this.jTextFieldmsg = jTextFieldmsg;
this.pClient = pClient;
}
public void sendMsg2Me(String msg) throws Exception{
byte[] data = msg.getBytes();
out.write(data);
out.flush();
}
public void run(){
//在线程run中调用处理节点的方法
process(this.client);
}
private void process(Socket client) {
try{
JbuttonmsgListener jbmsgListener = new JbuttonmsgListener(jTextFieldmsg,jTextArea,this);
jButton.addActionListener(jbmsgListener);
InputStream ins = client.getInputStream();
out = client.getOutputStream();
String string = " Hello,欢迎来的香煎马鲛鱼的服务器\r\n";
this.sendMsg2Me(string);
//调用读取字符串的方法,从输入流读取一个字符串
String insputS = readString(ins);
while(!insputS.equals("bye")){
string = "(客户端"+pClient.getName()+"消息)";
this.sendMsg2Me(string);
jTextArea.append(string);
insputS = readString(ins);
String string2 = null;
//System.out.println(string2);
//this.sendMsg2Me(insputS);
}
string = "大爷走好~~以后常来玩啊~~\r\n";
this.sendMsg2Me(string);
client.close();
insputS = readString(ins);
}
catch(Exception e){
}
}
private String readString(InputStream ins) throws Exception{
StringBuffer stb = new StringBuffer();
int i = ins.read();
char c = 0;
while(c!=13){
c = (char)i;
stb.append(c);
i = ins.read();
}
//将读到的字节组转为字符串,并调用trim去掉尾部的空格
String inputS =stb.toString().trim();
jTextArea.append(inputS);
return inputS;
}
}
//将发送信息的代码包装在一个方法中
客户端:
客户端需要的过程:
Socket client=new Socket(“服务器IP”,服务器端口);
只要如上代码执行成功,就算一个客户端连结上了服务器,接下来的流程和服务器端得到
Socket对象后的处理方式相同---从Socket对象上得到输入输出流;
注意:如果断开服务器时报错,那么这个错误是正常出现的,不是程序问题;
测试过程中,先关客户端,再关服务器,不然会报很多错误,也许还会导致编译器无法正常运行,一定注意~~~
package Client;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Clientserver extends JFrame{
public void Clientjfr(){
this.setSize(500,400);
this.setTitle("呵呵客户端");
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
//北部连接服务器
JLabel jLabelIp = new JLabel("Ip地址:");
JLabel jLabel = new JLabel("端口号:");
JButton jButton = new JButton("连接服务器");
JTextField jTextFieldIp = new JTextField("localhost");
JTextField jTextField = new JTextField("8090");
jTextFieldIp.setPreferredSize(new Dimension(100,30));
jTextField.setPreferredSize(new Dimension(100,30));
JPanel northjPanel = new JPanel();
//northjPanel.setSize(new Dimension(400,400));
northjPanel.add(jLabelIp);
northjPanel.add(jTextFieldIp);
northjPanel.add(jLabel);
northjPanel.add(jTextField);
northjPanel.add(jButton);
this.add(northjPanel,BorderLayout.NORTH);
//中部文本输入框:
JPanel jPanel = new JPanel();
JButton jButtoncenter = new JButton("发布消息");
JTextField jTextFieldcenter = new JTextField();
jTextFieldcenter.setPreferredSize(new Dimension(360,30));
jTextFieldcenter.setHorizontalAlignment(JTextField.LEFT);
jPanel.add(jButtoncenter);
jPanel.add(jTextFieldcenter);
this.add(jPanel,BorderLayout.CENTER);
//南部显示框
String abcString = "收到的信息在此处显示";
JPanel southjPanel = new JPanel();
JTextArea jTextAreasouth = new JTextArea();
jTextAreasouth.setPreferredSize(new Dimension(410,270));
jTextAreasouth.append(abcString);
southjPanel.add(jTextAreasouth);
this.add(southjPanel,BorderLayout.SOUTH);
this.setVisible(true);
JButtonListener jbListener = new JButtonListener(jTextField,jTextFieldIp,jTextFieldcenter,jTextAreasouth,jButtoncenter);
jButton.addActionListener(jbListener);
}
}
package Client;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import javax.swing.JTextArea;
public class Clientsotfware extends Thread {
private JTextArea jTextAreasouth;
private String ConnectIp;
private int port;
private OutputStream ouStream;// 到服务器的输出流
private InputStream ins;// 到服务器的输入流
public Clientsotfware(String ConnectIp, int port,JTextArea jTextAreasouth) {
this.ConnectIp = ConnectIp;
this.port = port;
this.jTextAreasouth = jTextAreasouth;
}
public boolean ConnectTerminal() {
try {
// 创建一个服务器端的Socket对象
Socket client = new Socket(ConnectIp, port);
ins = client.getInputStream();
// bfReader = new BufferedReader(new InputStreamReader(inStream));
ouStream = client.getOutputStream();
return true;
} catch (Exception e) {
}
return false;
}
public void run() {
while (true) {
readFromServer();
}
}
public void readFromServer() {
try {
String input = readString(ins);
System.out.println(input);
jTextAreasouth.append(input);
} catch (Exception e) {
e.printStackTrace();
}
}
public void senMsg(String msg) {
try {
msg += "\r\n";
this.ouStream.write(msg.getBytes());
//System.out.println("客户端要发送的消息:"+msg);
this.ouStream.flush();
jTextAreasouth.append("客户端要发送的消息"+msg);
} catch (Exception e) {
e.printStackTrace();
}
}
public String readString(InputStream ins) throws Exception {
StringBuffer stb = new StringBuffer();
int i = ins.read();
char c = 0;
while (c != 13) {
stb.append(c);
i = ins.read();
c = (char) i;
}
String inputs = stb.toString().trim();
return inputs;
}
}
package Client;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class JButtonListener implements ActionListener{
private JTextArea jTextAreasouth=null;
private JTextField jTextField=null;
private JTextField jTextFieldIp=null;
private JTextField jTextFieldmsg = null;
private JButton jButton=null;
public JButtonListener (JTextField jTextField,JTextField jTextFieldIp,JTextField jTextFieldmsg,JTextArea jTextAreasouth,JButton jButton){
this.jTextField = jTextField;
this.jTextFieldIp = jTextFieldIp;
this.jTextAreasouth = jTextAreasouth;
this.jTextFieldmsg = jTextFieldmsg;
this.jButton = jButton;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
int number=0;
String stnumber ="";
String str="0";
stnumber = jTextField.getText();
number = Integer.parseInt(stnumber);
str = jTextFieldIp.getText();
JframeThread jfThread = new JframeThread(number,str,jTextFieldmsg,jTextAreasouth,jButton);
jfThread.start();
}
}
package Client;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class JframeThread extends Thread{
private JTextArea jTextAreasouth;
private JTextField jTextFieldmsg;
private JButton jButton;
private int number;
private String str;
public JframeThread(int number,String str,JTextField jTextFieldmsg,JTextArea jTextAreasouth,JButton jButton){
this.number = number;
this.str = str;
this.jTextFieldmsg = jTextFieldmsg;
this.jTextAreasouth =jTextAreasouth;
this.jButton = jButton;
}
public void run(){
String msg=null;
Clientsotfware clientsotfware = new Clientsotfware(str,number,jTextAreasouth);
if(clientsotfware.ConnectTerminal()){
clientsotfware.start();
System.out.println("输入要发送的消息:");
SenMsgListener senListener = new SenMsgListener(clientsotfware,jTextFieldmsg);
jButton.addActionListener(senListener); }
}
}
package Client;
import java.util.Scanner;
publicclass netClient {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
Clientserver clserver = new Clientserver();
clserver.Clientjfr();
}
}
package Client;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTextField;
public class SenMsgListener implements ActionListener{
private Clientsotfware clientsotfware;
private JTextField jTextFieldmsg;
public SenMsgListener(Clientsotfware clientsotfware,JTextField jTextFieldmsg) {
// TODO Auto-generated constructor stub
this.clientsotfware = clientsotfware;
this.jTextFieldmsg = jTextFieldmsg;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
clientsotfware.senMsg(jTextFieldmsg.getText());
jTextFieldmsg.setText("");
}
}