1. 描写TCP、UDP数据帧格式,并比较TCP和UDP的区别。
协议类型
源IP
目的IP
源端口
目的端口
帧序号
帧数据
在协议类型里填写是TCP还是UDP连接
TCP是基于有效连接的通信,在源和目的地址建立有效连写之后再进行通信。
UDP是用户数据报,它不基于有效的连接,直接进行数据通信。
2. 画图说明应用程序、Socket、网络驱动程序之间的数据传递过程和工作关系。
数据发送过程
1) 应用程序要发送数据时,由应用程序产生一个socket
2) 应用程序调用bind方法将socket的信息通知给驱动程序(IP地址,端口号)
3) 绑定之后,应用程序开始向Socket发送数据
4) 驱动程序从Socket取出数据,并通过网卡发送出去
数据接收过程:
1) 由应用程序产生一个Socket
2) 应用程序调用bind方法把Soket通知给驱动程序
3) 驱动程序把数据处理后传递到Socket中
4) 应用程序不停的查询Socket,取出数据。
3. 自己编写出UDP网络聊天程序。
package chat;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.net.*;
public class Chat extends Frame {
List lst=new List(6);//定义一个接收聊天信息的列表
TextField tfIP=new TextField(15);//定义输入ip信息的文本框
TextField tfData=new TextField(20);//定义发动聊天信息的文本框
DatagramSocket ds=null;//定义一个socket
public Chat()
{
try {
ds=new DatagramSocket(3000);//实例化一个soket对象,端口号为3000
} catch (SocketException e1) {
e1.printStackTrace();
}
this.add(lst,"Center");//把聊天信息的列表添加在主窗口的中间
Panel p=new Panel();//定义一个面板
this.add(p,"South");//把面板添加到主窗口的下部
p.setLayout(new BorderLayout());//定义该面板的布局格式
p.add(tfIP,"West");//把输入ip信息的框定义在面板左侧
p.add(tfData,"East");//把对话框定义在面板右侧
new Thread(new Runnable()
{
public void run() {
byte []buf=new byte[1024];//定义一个字节数组
DatagramPacket dp=new DatagramPacket(buf,1024);//定义一个接收数据的数据包
while (true) {//循环读取数据
try {
ds.receive(dp);//通过soket向包中读取数据
String infoString=new String(dp.getData(),0,dp.getLength());//把接收到的数据转化为字符串
lst.add(infoString+" from"+dp.getAddress().getHostAddress()+":"+dp.getPort(),0);//显示接收到的数据,和该数据的传送ip和端口号
} catch (IOException e) {
if (!ds.isClosed()) {
e.printStackTrace();//如果不是因为soket关闭引起的异常则显示
}
}
}
}
}).start();//开启该线程
tfData.addActionListener(new ActionListener(){//编写文本输入框的监听器
public void actionPerformed(ActionEvent arg0) {
byte []buf=tfData.getText().getBytes();//定义一个字节数组,用来接收文本输入框的数据
try {
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName(tfIP.getText()),3000);//把字节数组中的数据导入到数据包里,并声明数据发送的ip和端口号
ds.send(dp);//发送数据
tfData.setText("");//清空文本输入框
} catch (Exception e) {
e.printStackTrace();
}
}
});
addWindowListener(new WindowAdapter(){//关闭按钮的响应事件
public void windowClosing(WindowEvent e)
{
ds.close();
dispose();
System.exit(0);
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("starting ...");
Chat t=new Chat();
t.setSize(300, 400);//设置窗口的大小
t.setTitle("Chat");
t.setVisible(true);
t.setResizable(false);
}
}
4. 结论
在程序改成
pw.print(strLine+"-->"+strEcho+"/r/n");和
pw.print(strLine+"-->"+strEcho+System.getProperty("line.separator"));
时在客户端输入数据,服务端接受到传入的数据,但是没有返回数据
加上一行代码
pw.flush();
输入数据后,有翻转的数据返回
结论:println里附加了一个刷新缓存的功能
5. 用文件指定端口号
byte [] buf=new byte[1024];//定义一个接收数据的数组
File file=new File("1.txt");//读取一个名为1.txt的文件,里边存储了端口号
FileInputStream in=new FileInputStream(file);//建立文件输入流
int len=in.read(buf);//把文件中的数据读到数组中,并返回读取字符串的长度
String port=new String(buf,0,len);//把读取到的字符转化为字符串
int portInt=Integer.parseInt(port);//把字符串转化为整数
in.close();//关闭文件输入流