TCP协议开发Word文档下载推荐.docx
《TCP协议开发Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《TCP协议开发Word文档下载推荐.docx(18页珍藏版)》请在冰豆网上搜索。
四、需要完成的内容
需要有基本的双人、多人文字聊天功能,上下线通知,在线用户列表,点对点文件传输,所有的文字或文件传输需支持CRC-32校验,具有出错重传机制。
五、设计步骤
在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Servermodel)。
该模式的建立基于以下两点:
(1)非对等作用;
(2)通信完全是异步的。
客户机/服务器模式在操作过程中采取的是主动请示方式:
1、首先服务器方要先启动,并根据请示提供相应服务,其过程如下:
(1)打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。
(2)等待客户请求到达该端口。
(3)接收到重复服务请求,处理该请求并发送应答信号。
(4)返回第二步,等待另一客户请求
(5)关闭服务器。
2、客户方:
(1)打开一通信通道,并连接到服务器所在主机的特定端口。
(2)向服务器发送服务请求报文,等待并接收应答;
继续提出请求……
(3)请求结束后关闭通信通道并终止。
3、TCP连接的套接字的系统调用时序图如图2.1所示。
4、TCP连接的应用程序流程图如图2.2所示。
六、设计报告要求
见《课程设计报告》
图2.1TCP连接的套接字的系统调用时序图
图2.2TCP连接的应用程序流程图
七、实验代码
(1)客户机模式:
usingSystem;
usingSystem.Windows.Forms;
//添加的命名空间引用
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Threading;
usingSystem.IO;
namespaceSyncChatClient
{
publicpartialclassMainForm:
Form
{
privateboolisExit=false;
privateTcpClientclient;
privateBinaryReaderbr;
privateBinaryWriterbw;
publicMainForm()
InitializeComponent();
Randomr=newRandom((int)DateTime.Now.Ticks);
textBoxUserName.Text="
user"
+r.Next(100,999);
listBoxOnlineStatus.HorizontalScrollbar=true;
}
///<
summary>
///【连接服务器】按钮的Click事件
/summary>
privatevoidbuttonConnect_Click(objectsender,EventArgse)
buttonConnect.Enabled=false;
try
//此处为方便演示,实际使用时要将Dns.GetHostName()改为服务器域名
client=newTcpClient("
192.168.1.43"
51888);
AddTalkMessage("
连¢
?
接¨
®
成¨
¦
功|"
);
catch
失º
¡
ì
败ã
¨
¹
"
buttonConnect.Enabled=true;
return;
//获取网络流
NetworkStreamnetworkStream=client.GetStream();
//将网络流作为二进制读写对象
br=newBinaryReader(networkStream);
bw=newBinaryWriter(networkStream);
SendMessage("
Login,"
+textBoxUserName.Text);
ThreadthreadReceive=newThread(newThreadStart(ReceiveData));
threadReceive.IsBackground=true;
threadReceive.Start();
处理接收的服务器端数据<
privatevoidReceiveData()
stringreceiveString=null;
while(isExit==false)
//从网络流中读出字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString=br.ReadString();
if(isExit==false)
MessageBox.Show("
与服务器失去联系"
break;
string[]splitString=receiveString.Split('
'
stringcommand=splitString[0].ToLower();
switch(command)
case"
login"
:
//格式:
login,用户名
AddOnline(splitString[1]);
logout"
logout,用户名
RemoveUserName(splitString[1]);
talk"
talk,用户名,对话信息
//AddTalkMessage(splitString[1]+"
:
\r\n"
//AddTalkMessage(receiveString.Substring(
//splitString[0].Length+splitString[1].Length+2));
AddTalkMessage(string.Format("
[{0}]说:
{1}"
splitString[1],receiveString.Substring(
splitString[0].Length+splitString[1].Length+2)));
default:
什么意思啊:
+receiveString);
Application.Exit();
向服务器端发送信息<
privatevoidSendMessage(stringmessage)
//将字符串写入网络流,此方法会自动附加字符串长度前缀
bw.Write(message);
bw.Flush();
发送失败!
【发送】按钮的的Click事件<
privatevoidbuttonSend_Click(objectsender,EventArgse)
if(listBoxOnlineStatus.SelectedIndex!
=-1)
//SendMessage("
Talk,"
+listBoxOnlineStatus.SelectedItem+"
"
+textBoxSend.Text+"
+textBoxSend.Text);
textBoxSend.Clear();
else
请?
先¨
在¨
²
[当Ì
À
前¡
ã
线?
]中D选?
择?
一°
个?
对?
话¡
者?
关闭窗口时触发的事件<
privatevoidMainForm_FormClosing(objectsender,FormClosingEventArgse)
//未与服务器连接前client为null
if(client!
=null)
Logout,"
isExit=true;
br.Close();
bw.Close();
client.Close();
在发送信息文本框中按下【Enter】键触发的事件<
privatevoidtextBoxSend_KeyPress(objectsender,KeyPressEventArgse)
if(e.KeyChar==(char)Keys.Return)
//触发buttonSend的Click事件
buttonSend.PerformClick();
privatedelegatevoidMessageDelegate(stringmessage);
在¨
richTextBoxTalkInfo中追加聊天信息<
privatevoidAddTalkMessage(stringmessage)
if(richTextBoxTalkInfo.InvokeRequired)
MessageDelegated=newMessageDelegate(AddTalkMessage);
richTextBoxTalkInfo.Invoke(d,newobject[]{message});
richTextBoxTalkInfo.AppendText(message+Environment.NewLine);
richTextBoxTalkInfo.ScrollToCaret();
privatedelegatevoidAddOnlineDelegate(stringmessage);
listBoxOnlineStatus中D添加在线的其他客户端信息<
privatevoidAddOnline(stringuserName)
if(listBoxOnlineStatus.InvokeRequired)
AddOnlineDelegated=newAddOnlineDelegate(AddOnline);
listBoxOnlineStatus.Invoke(d,newobject[]{userName});
listBoxOnlineStatus.Items.Add(userName);
listBoxOnlineStatus.SelectedIndex=listBoxOnlineStatus.Items.Count-1;
listBoxOnlineStatus.ClearSelected();
privatedelegatevoidRemoveUserNameDelegate(stringuserName);
listBoxOnlineStatus中D移除不在线的其它客户ì
端信息<
privatevoidRemoveUserName(stringuserName)
RemoveUserNameDelegated=RemoveUserName;
listBoxOnlineStatus.Invoke(d,userName);
listBoxOnlineStatus.Items.Remove(userName);
privatevoidMainForm_Load(objectsender,EventArgse)
}}}
(2)服务器模式:
usingSystem.Collections.Generic;
namespaceSyncChatServer
保存连接的所有用户<
privateList<
User>
userList=newList<
();
使用本机的IP地址¤
<
IPAddresslocalAddress;
监听端口<
privateconstintport=51888;
privateTcpListenermyListener;
是否正常退出所有接受线程<
boolisNormalExit=false;
listBoxStatus.HorizontalScrollbar=true;
IPAddress[]addrIP=Dns.GetHostAddresses(Dns.GetHostName());
localAddress=addrIP[0];
buttonStop.Enabled=false;
【开始监听】按钮的Click事件<
privatevoidbuttonStart_Click(objectsender,EventArgse)
myListener=newTcpListener(localAddress,port);
myListener.Start();
AddItemToListBox(string.Format("
开始在{0}:
{1}监听客户连接"
localAddress,port));
//创建一个线程监听客户端连接请求
ThreadmyThread=newThread(ListenClientConnect);
myThread.Start();
buttonStart.Enabled=false;
buttonStop.Enabled=true;
接受客户端连接<
privatevoidListenClientConnect()
TcpClientnewClient=null;
while(true)
newClient=myListener.AcceptTcpClient();
//当单击停止监听或者退出此窗体时AcceptTcpClient()会产生异常
//因此可以利用此异常退出循环
//每接受一个客户端连接,就创建一个对应的线程循环接受该客户端发来的信息
Useruser=newUser(newClient);
ThreadthreadReceive=newThread(ReceiveData);
threadReceive.Start(user);
userList.Add(user);
[{0}]进入"
newClient.Client.RemoteEndPoint));
当前连接用户数:
{0}"
userList.Count));
///处理接受的客户端数据
paramname="
userState"
>
客户端信息<
/param>
privatevoidReceiveData(objectuserState)
Useruser=(User)userState;
TcpClientclient=user.client;
while(isNormalExit==false)
//从网络流中读出字符串,此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString=user.br.ReadString();
if(isNormalExit==false)
与[{0}]失去联系,已终止接收该用户信息"
client.Client.RemoteEndPoint));
RemoveUser(user);
来自[{0}]:
user.client.Client.RemoteEndPoint,receiveString));
string[]splitString=receiveString.Split('
switch(splitString[0])
Login"
user.userName=splitString[1];
SendToAllClient(user,receiveString);
Logout"
Talk"
stringtalkString=receiveString.Substring(splitString[0].Length+splitString[1].Length+2);
{0}对{1}说:
{2}"
user.userName,splitString[1],talkString));
SendToClient(user,"
talk,"
+user.userName+"
+talkString);
foreach(UsertargetinuserList)
if(target.userName==splitString[1]&
&
user.userName!
=splitString[1])
SendToClient(target,"
AddItemToListBox("
什么意思啊?
"
///发送message给user
指定发给哪个用户<
message"
信息内容<
privatevoidSendToClient(Useruser,stringmessage)
user.bw.Write(message);
user.bw.Flush();
向[{0}