一、TCP的基本概念
TCP是专门设计用于在不可靠的英特网上提供可靠的、端到端的字节流通信的协议,是一个面向连接的协议,TCP连接是字节流而非报文流。UDP和TCP各有65536个端口号互不影响。
二、单线程服务端
以下代码只能实现服务端和客户端的同步对话。服务端处理完一个客户端请求,才会处理另一个客户端请求。服务器端的输出效果是Client1阻塞20秒,Client2不会执行。必须等Client1阻塞结束之后,Client2才会执行。该例子可用来学习TCP的基本语法。
/**
* TCP客户端1
*
* @author 徐越
*
*/
publicclassClient1
{
publicstaticvoidmain(String[] args)throwsException
{
Socket socket =newSocket("127.0.0.1",8821);
OutputStream os = socket.getOutputStream();
String msg ="我是徐越1";
Thread.sleep(20000);
os.write(msg.getBytes());
os.flush();
os.close();socket.close();
}
}
/**
* TCP客户端2
*
* @author 徐越
*
*/
publicclassClient2
{
publicstaticvoidmain(String[] args)throwsException
{
Socket socket =newSocket("127.0.0.1",8821);
OutputStream os = socket.getOutputStream();
String msg ="我是徐越2";
os.write(msg.getBytes());
os.flush();
os.close();socket.close();
}
}
/**
* 单线程TCP服务端
*
* @author 徐越
*
*/
publicclassServer
{
publicstaticvoidmain(String[] args)throwsException
{
// 创建端口为8821的TCP服务器端对象
// 8821是服务器端的端口号而客户端从某端口A连到8821,端口A是随机的
ServerSocket serverSocket =newServerSocket(8821);
while(true)
{
// 若无客户端发送请求则线程在此阻塞,方法不继续执行
Socket socket = serverSocket.accept();
System.out.println("connected");
InputStream instream = socket.getInputStream();
ByteArrayOutputStream bos =newByteArrayOutputStream();
intlen =0;
byte[] buffer =newbyte[1024];
while((len = instream.read(buffer)) != -1)
{
bos.write(buffer,0, len);
}
instream.close();
bos.flush();
bos.close();
String msg = bos.toString();
System.out.println("客户端的IP:"+ socket.getInetAddress().getHostAddress());
System.out.println("客户端的端口:"+ socket.getPort());
System.out.println("客户端的信息:"+ msg);
}
}
}
执行结果
connected
客户端的IP:127.0.0.1
客户端的端口:3775
客户端的信息:我是徐越1
connected
客户端的IP:127.0.0.1
客户端的端口:3787
客户端的信息:我是徐越2
三、多线程服务器
在实际应用中是在服务器上运行一个永久的程序,接收来自其他多个客户端的请求,提供相应的服务。需要利用多线程实现多客户机制。服务器在指定的端口上监听是否有客户请求,一旦监听到就会启动一个专门的服务线程来响应该请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。只要将服务端为如下代码,Client1和Client2就会异步执行。
/**
* 多线程服务端0
*
* @author 徐越
*
*/
publicclassMultiThreadServer0
{
// 端口号
privateintport =8821;
// 服务端
privateServerSocket serverSocket;
publicMultiThreadServer0()throwsIOException
{
// 创建服务器端
serverSocket =newServerSocket(port);
System.out.println("服务器启动");
}
publicvoidservice()
{
while(true)
{
Socket socket =null;
try
{
// 客户端进行连接时会触发accept方法从而建立连接
socket = serverSocket.accept();
newMultiThreadHandler(socket).start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
publicstaticvoidmain(String[] args)throwsIOException
{
newMultiThreadServer1().service();
}
}
/**
* 多线程处理类
*/
classMultiThreadHandlerextendsThread
{
privateSocket socket;
publicMultiThreadHandler(Socket socket)
{
this.socket = socket;
}
privateBufferedReader getReader(Socket socket)throwsIOException
{
InputStream socketIn = socket.getInputStream();
// InputStreamReader为转换流
// InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流
InputStreamReader isr =newInputStreamReader(socketIn);
returnnewBufferedReader(isr);
}
publicvoidrun()
{
try
{
BufferedReader br = getReader(socket);
String msg =null;
while((msg = br.readLine()) !=null)
{
System.out.println("客户端的IP:"+ socket.getInetAddress().getHostAddress());
System.out.println("客户端的端口:"+ socket.getPort());
System.out.println("客户端的信息:"+ msg);
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(socket !=null)
{
socket.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
/**
* 多线程服务端1
*/
publicclassMultiThreadServer1
{
// 端口号
privateintport =8821;
// 服务端
privateServerSocket serverSocket;
// 线程池
privateExecutorService executorService;
// 单个CPU线程池大小
privatefinalintPOOL_SIZE =10;
publicMultiThreadServer1()throwsIOException
{
// 创建服务器端
serverSocket =newServerSocket(port);
// 获取当前系统的CPU数目
intcpuNums = Runtime.getRuntime().availableProcessors();
// 根据系统资源情况灵活定义线程池大小
executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE);
System.out.println("服务器启动");
}
publicvoidservice()
{
while(true)
{
Socket socket =null;
try
{
// 客户进行连接就会触发accept方法从而建立连接
socket = serverSocket.accept();
// 调用线程池操作
executorService.execute(newHandler(socket));
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
publicstaticvoidmain(String[] args)throwsIOException
{
newMultiThreadServer1().service();
}
}
/**
* 多线程处理类
*/
classHandlerimplementsRunnable
{
privateSocket socket;
publicHandler(Socket socket)
{
this.socket = socket;
}
privateBufferedReader getReader(Socket socket)throwsIOException
{
InputStream socketIn = socket.getInputStream();
// InputStreamReader为转换流
// InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流
InputStreamReader isr =newInputStreamReader(socketIn);
returnnewBufferedReader(isr);
}
publicvoidrun()
{
try
{
BufferedReader br = getReader(socket);
String msg =null;
while((msg = br.readLine()) !=null)
{
System.out.println("客户端的IP:"+ socket.getInetAddress().getHostAddress());
System.out.println("客户端的端口:"+ socket.getPort());
System.out.println("客户端的信息:"+ msg);
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(socket !=null)
{
socket.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
两个多线程服务端执行结果相同
服务器启动
客户端的IP:127.0.0.1
客户端的端口:3931
客户端的信息:我是徐越2
客户端的IP:127.0.0.1
客户端的端口:3928
客户端的信息:我是徐越1
参考地址:http://www.2cto.com/kf/201209/158518.html