Socket通信
第一节 socket通信的服务端和客户端的代码大致结构
一、服务端代码结构(红色字体处为关键代码)
try {
ServerSocket server = new ServerSocket(4567);
//创建一个ServerSocket,设定监听端口号
Socket socket = server.accept();
//accept()方法会阻塞,直到客户请求的到来;
//有客户请求到来则产生一个Socket对象,此时连接建立起来,并继续执行
InputStream is = socket.getInputStream();
//从Socket对象中获取输入流
//接下来可以将输入流再次包装,如:
//sin = new BufferedReader(new InputStreamReader(is));
OutputStream os = socket.getOutputStream();
//从Socket对象中获取输出流
//接下来可以将输出流再次包装,如:
//sout = new DataOutputStream(os);
while(flag)
{
利用输入流或输入流的包装流、输出流或输出流的包装流 来接收或发出信息
//在某些必要的时候设法跳出死循环
}
//以下是结束通信需要使用的代码
os.close();
is.close();
socket.close();
server.close();//如果服务端需要继续等待新的客户端来连接,则不使用此句
System.exit(0);//如果服务端需要停止运行,才使用此
}
catch (IOException e) {System.out.println(e);}
二、客户端代码结构(红色字体处为关键代码)
try {
Socket socket = new Socket("localhost", 4567);
//向服务端发出请求,参数设定了服务端的主机号和监听端口
//如果连接服务端不成功,该构造方法new Socket(…)会抛出IOException;
//如果连接服务端成功,则产生一个Socket对象,此时连接建立起来,并继续执行
InputStream is = socket.getInputStream();
//从Socket对象中获取输入流
//这里可以将输入流再次包装,如:
//sin = new BufferedReader(new InputStreamReader(is));
OutputStream os = socket.getOutputStream();
//从Socket对象中获取输出流
//这里可以将输出流再次包装,如:
//sout = new DataOutputStream(os);
while(flag)
{
利用输入流或输入流的包装流、输出流或输出流的包装流 来接收或发出信息
//在某些必要的时候设法跳出死循环
}
//以下是结束通信需要使用的代码
os.close();
is.close();
socket.close();
System.exit(0); //如果客户端需要停止运行,才使用此
}
catch (IOException e) {System.out.println(e);}
总结:我猜想
1.服务端维持一个ServerSocket对象,一个Socket对象;客户端维持一个Socket对象;
服务端维持的这个Socket对象与客户端维持的这个Socket对象互为一一对应。
2.当客户端Socket对象关闭,相应的服务端Socket对象也应当紧接着关闭;
3.如果服务端需要有与多个客户端通信的能力,那么应当始终监听,即有一个线程始终执行下述语句:
Socket socket = server.accept();
欲实现此目的,代码应含有下述代码结构:
While(true)
{
...
Socket socket = server.accept();
...
}
第二节示例
本示例参见参见《Java程序设计》宋中山严山钧的P297。
本示例欲使服务端的接收和发送同时进行,因此又开启了一个线程
本示例欲使客户端的接收和发送同时进行,因此又开启了一个线程
一、服务端代码:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
publicclass Server implements Runnable {
ServerSocket server = null;
Socket socket = null;
Boolean flag = true;
Thread c;
BufferedReader sin;
DataOutputStream sout;
publicstaticvoid main(String[] args) {
new Server().serverStart();
}
publicvoid serverStart() {
try {
server = new ServerSocket(4567);
System.out.println("端口号:" + server.getLocalPort());
socket = server.accept();
InputStream is = socket.getInputStream();
sin = new BufferedReader(new InputStreamReader(is));
OutputStream os = socket.getOutputStream();
sout = new DataOutputStream(os);
c = new Thread(this);
c.start();
String aline;
while (flag) //该块用于接收
{
while ((aline = sin.readLine()) != null)
//如果客户端关闭,这里读出的将为null。该块用于发送
//该循环跳出后,应调用一次flag = false;
{
System.out.println("客户端对服务器说" + aline);
if (aline.equals("bye")) {
flag = false;
break;
}
}
flag = false;
}
sout.close();
os.close();
sin.close();
is.close();
socket.close();
System.exit(0);
} catch (IOException e) {
System.out.println(e);
}
}
publicvoid run() { //该块用于发送
while (true) {
try {
int ch;
while ((ch = System.in.read()) != -1) {
sout.write((byte) ch);
if (ch == '\n')
sout.flush();
}
} catch (IOException e) {
System.out.println(e);
}
}
}
publicvoid finalize() {
try {
server.close();
} catch (IOException e) {
System.out.println(e);
}
}
}
二、客户端代码
import java.io.*;
import java.net.Socket;
publicclass Client implements Runnable {
Socket socket = null;
Boolean flag = true;
Thread c;
BufferedReader sin;
DataOutputStream sout;
publicstaticvoid main(String[] args) {
new Client().clientStart();
}
publicvoid clientStart() {
try {
socket = new Socket("localhost", 4567);
System.out.println("已建立连接");
InputStream is = socket.getInputStream();
sin = new BufferedReader(new InputStreamReader(is));
OutputStream os = socket.getOutputStream();
sout = new DataOutputStream(os);
c = new Thread(this);
c.start();
String aline;
while (flag) //该块用于接收
{
while ((aline = sin.readLine()) != null)
//如果客户端关闭,这里读出的将为null。
//该循环跳出后,应调用一次flag = false;
{
System.out.println("服务端对客户端说" + aline);
if (aline.equals("bye")) {
flag = false;
break;
}
}
flag = false;
}
sout.close();
os.close();
sin.close();
is.close();
socket.close();
System.exit(0);
} catch (IOException e) {
System.out.println(e);
}
}
publicvoid run() { //该块用于发送
while (true) {
try {
int ch;
while ((ch = System.in.read()) != -1)
{
sout.write((byte) ch);
if (ch == '\n')
sout.flush();
}
} catch (IOException e) {
System.out.println(e);
}
}
}
}