关于socket的异步与同步通信

先贴代码:客户端的代码

package connect;



import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
public class ConnectTest extends Thread{
// private String ip;//客户端需要连接的IP地址
// private int port; //客户端需要连接的端口号
// private String cmd;  //客户端想要发送的命令
// //通过构造函数确定需要连接什么样的服务器和端口
// public ConnectTest(String ip,int port) {
// super();
// this.ip = ip;
// this.port = port;
// }
// //同上,初始化send的条件
// public ConnectTest(String ip, int port, String cmd) {
// super();
// this.ip = ip;
// this.port = port;
// this.cmd = cmd;
// }
//       
// //重写线程方法
// public void run(){
// A.sendMsg(ip, port,cmd);
// }
/*
* 主函数开启多线程去发送信息
*/

// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// String ip = "127.0.0.1";
// int port1 = 1234;
// int port2 = 1235;
// ConnectTest c = new ConnectTest(ip,port2,"123456");
// for (int i = 0; i < 8; i++) {
// ConnectTest test = new ConnectTest(ip, port1,i+"");
// test.start();
// }
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// c.start();
public static void main(String[] args) {

A.sendMsg("127.0.0.1", 1234, "aaa");
A.sendMsg("127.0.0.1", 1234, "bbb");
A.sendMsg("127.0.0.1", 1234, "ccc");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
A.sendMsg("127.0.0.1", 1235, "ddd");
A.sendMsg("127.0.0.1", 1234, "eee");

}
}
//内部类确定对象唯一性,这样的话是同一类对象的线程会互斥,不是同一类对象的线程则是异步,用端口号来确定是否是同一对象。
class A{
private static HashMap<String,A> map = new HashMap<String, A>();
private String ip;
private int port;
private A(String ip,int port) {
this.ip = ip;
this.port = port;
}
//为了创建单例对象
public synchronized static A getA(String ip,int port){
String key = getKey(ip, port);
if(map.containsKey(key)){
return map.get(key);
}else{
A a = new A(ip,port);
map.put(key, a);
return a;
}
}

private static String getKey(String ip,int port){
return ip+":"+port;
}
//锁同步方法可区别不同类去锁只有同一个类访问会锁上,不是同一个类不会锁
public  synchronized void sendMsg(String msg){
DataOutputStream dos=null;
DataInputStream dis =null;
Socket s=null;
try {
//获取服务端的连接
s=new Socket(ip,port);
//获取socket对象的输出流
dos = new DataOutputStream(s.getOutputStream());
//获取socket对象的输入流,读取客户端的回复
dis=new DataInputStream(s.getInputStream());
//客户端进行写数据
dos.writeUTF(msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
dos.flush();
String msg_return = null;
if((msg_return = dis.readUTF())!=null){
System.out.println(getKey(ip, port)+"----"+"re:"+msg_return);
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//封装发送命令的方法。
public static void sendMsg(String ip,int port,String cmd){
new Thread(new MyRunnable(ip, port, cmd)).start();

}

}


class MyRunnable implements Runnable{
private String ip;
private int port;
private String cmd;

public MyRunnable(String ip, int port, String cmd) {
super();
this.ip = ip;
this.port = port;
this.cmd = cmd;
}


@Override
public void run() {
// TODO Auto-generated method stub
A a = A.getA(ip,port);
a.sendMsg(cmd);
}

}


我这里开了两个端口去连接服务器。说一下要求,连接同一个端口时是互斥的也就是他们会阻塞,连接的如果是不同端口,那他们就各自执行各自的。互不影响。

然后是服务端,有人会问服务端怎么监听两个或者多个端口,下面的代码可以实现监听多个端口

服务端代码:

package connect;



import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;


/**
 * 服务器
 * @author Administrator
 *
 */
public class Server extends Thread{
   public int port;//公共相同的地址,只是根据端口不同,开启不同的线程
   
   public Server(int port){
  this.port=port;
   }
   //客户端根据不同的端口或者相同的端口进行写信息
@Override
public  void run() {
try {
ServerSocket ss=new ServerSocket(port);//监听不同的端口
while(true){
Socket s=ss.accept();//获得与服务器对应的socket
//获得输入流进行读操作
DataInputStream dis=new DataInputStream(s.getInputStream());
DataOutputStream dos=new DataOutputStream(s.getOutputStream());
    String content= dis.readUTF();
    //回复客户端
    dos.writeUTF(change(content));
    if(content!=null){
    System.out.println("来自客户端的输出:"+content);
    }

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

}
public static void main(String[] args) {
Server s1=new Server(1234);
Server s2=new Server(1235);
s1.start();
s2.start();
}
/**

* @param b 任意字符串
* @return
* 通过该方法可以将小写字母转为大写字母,也可以将大写字母转换为小写字母
*/
public static String change(String b) {
 char letters[] = new char[b.length()];
 for(int i=0;i<b.length();i++){
  
  char letter = b.charAt(i);
  if(letter>='a' && letter<='z')
   letter = (char) (letter-32);
  else if(letter>='A' && letter<='Z')
   letter = (char) (letter+32);
  letters[i] = letter;
 }
 
 return new String(letters);

}


}

因为服务端要对客户端进行回复,所以我就找了个字母转换的方法。这样就可以实现效果。

然后是运行截图:

先启动服务端:关于socket的异步与同步通信

然后是客户端:

关于socket的异步与同步通信

我们再看服务器端的输出:关于socket的异步与同步通信

这样就基本实现了所谓的socket的同步通信与异步通信了。上面用了客户端使用了HashMap有人知道是为什么吗?等回复。。。