目录
TCP/IP协议介绍
Java中socket编程
测试结果
TCP/IP协议介绍
TCP/IP协议包含的范围非常的广,它是一种四层协议,包含了各种硬件、软件需求的定义。TCP/IP协议确切的说法应该是TCP/UDP/IP协议。UDP协议(User Datagram Protocol 用户数据报协议),是一种保护消息边界的,不保障可靠数据的传输。TCP协议(Transmission Control Protocol 传输控制协议),是一种流传输的协议。他提供可靠的、有序的、双向的、面向连接的传输。
保护消息边界,就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包。
而面向流则是指无保护消息边界的,如果发送端连续发送数据,接收端有可能在一次接收动作中,会接收两个或者更多的数据包。
举例来说,假如,我们连续发送三个数据包,大小分别是2k、4k、8k,这三个数据包都已经到达了接收端的网络堆栈中,如果使用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有三次接收动作,才能够把所有的数据包接收完。而使用TCP协议,我们只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的数据包接收下来,只需要有一次接收动作。
这就是因为UDP协议的保护消息边界使得每一个消息都是独立的。而流传输,却把数据当作一串数据流,它不认为数据是一个一个的消息。所以有很多人在使用TCP协议通讯的时候,并不清楚TCP是基于流的传输,当连续发送数据的时候,他们时常会认为TCP会丢包。其实不然,因为当它们使用的缓冲区足够大时,它们有可能会一次接收到两个甚至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个数据包,而已经接收的其它据包却被忽略了。
Java中socket编程
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.IOException;
import java.lang.String;
public class liaotian extends JFrame{
private static final int DEFAULT_PORT=8899;
private JLabel stateLB;
private JTextArea centerTextArea;
private JPanel southPanel;
private JTextArea inputTextArea;
private JPanel bottomPanel;
private JTextField ipTextField;
private JTextField remotePortTF;
private JButton sendBT;
private JButton clearBT;
private DatagramSocket datagramSoket;
private void setUpUI(){
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setResizable(false);//窗口大小不可改变
setLocationRelativeTo(null);//设置窗口相对于指定组件的位置
stateLB=new JLabel("weijianting");
stateLB.setHorizontalAlignment(JLabel.RIGHT);
centerTextArea=new JTextArea();
centerTextArea.setEditable(false);
centerTextArea.setBackground(new Color(211,211,211));
southPanel=new JPanel(new BorderLayout());
inputTextArea=new JTextArea(5,20);
bottomPanel=new JPanel(new FlowLayout(FlowLayout.CENTER,5,5));
ipTextField=new JTextField("127.0.0.1",8);
remotePortTF=new JTextField(String.valueOf(DEFAULT_PORT),3);
sendBT=new JButton("发送");
clearBT=new JButton("清屏");
bottomPanel.add(ipTextField);
bottomPanel.add(remotePortTF);
bottomPanel.add(sendBT);
bottomPanel.add(clearBT);
southPanel.add(new JScrollPane(inputTextArea),BorderLayout.CENTER);
southPanel.add(bottomPanel,BorderLayout.SOUTH);
add(stateLB,BorderLayout.NORTH);
add(new JScrollPane(centerTextArea),BorderLayout.CENTER);
add(southPanel,BorderLayout.SOUTH);
setVisible(true);
}
private void setListener(){
sendBT.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
final String ipAddress=ipTextField.getText();
final String remotePort=remotePortTF.getText();
if(ipAddress==null||ipAddress.trim().equals("")||remotePort==null||remotePort.trim().equals("")){
JOptionPane.showMessageDialog(liaotian.this,"请输入IP地址和端口号");
return;
}
if(datagramSoket==null||datagramSoket.isClosed()){
JOptionPane.showMessageDialog(liaotian.this,"监听未成功");
return;
}
String sendContent=inputTextArea.getText();
byte[] buf=sendContent.getBytes();
try{
centerTextArea.append("我对"+ipAddress+":"+remotePort+"说:\n"+inputTextArea.getText()+"\n\n");
centerTextArea.setCaretPosition(centerTextArea.getText().length());
datagramSoket.send(new DatagramPacket(buf,buf.length,InetAddress.getByName(ipAddress),Integer.parseInt(remotePort)));
inputTextArea.setText("");
}catch(IOException e1){
JOptionPane.showMessageDialog(liaotian.this, "出错了,发送不成功");
e1.printStackTrace();
}
};
});
clearBT.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
centerTextArea.setText("");
}
});
}
private void initSocket(){
int port=DEFAULT_PORT;
while(true){
try{
if(datagramSoket!=null&&!datagramSoket.isConnected()){
datagramSoket.close();
}
try{
port=Integer.parseInt(JOptionPane.showInputDialog(this,"请输入端口号","端口号",JOptionPane.QUESTION_MESSAGE));
if(port<1||port>65535){
throw new RuntimeException("端口号超出范围");
}
}catch(Exception e){
JOptionPane.showMessageDialog(null,"你输入的端口不正确,请输入1~65535之间的数");
continue;
}
datagramSoket=new DatagramSocket(port);
startListen();
stateLB.setText("已在"+port+"端口监听");
break;
}catch(SocketException e){
JOptionPane.showMessageDialog(this, "端口号被占用,请重新设置端口");
stateLB.setText("当前未启动监听");
}
}
}
private void startListen(){
new Thread(){
private DatagramPacket p;
public void run(){
byte[] buf=new byte[1024];
p=new DatagramPacket(buf,buf.length);
while(!datagramSoket.isConnected()){
try{
datagramSoket.receive(p);
centerTextArea.append(p.getAddress().getHostAddress()+":"+((InetSocketAddress)p.getSocketAddress()).getPort()+"对我说:\n"+new String(p.getData(),0,p.getLength())+"\n\n");
centerTextArea.setCaretPosition(centerTextArea.getText().length());
}catch(IOException e){
e.printStackTrace();
}
}
}
}.start();
}
public static void main(String[] args) {
liaotian a=new liaotian();
a.setUpUI();
a.initSocket();
a.setListener();
}
}
测试结果