用C#做TCP网上聊天客户端,最麻烦的恐怕是IP地址问题了。其基本原理应该是这样的:服务器端要使用一个公网的IP,这样就可以在这个互联网上跟任意一台机器聊天了。因为服务器需要随时侦听客户端的聊天请求。而要使得客户端可以访问它,在互联网上必须使用公网的IP和域名。
怎么让服务器的公网IP和域名固定下来呢?如果你使用的ADSL,那么你具有的是可变的公网IP,这时,你不妨申请一个域名,例如花生壳工具,可以申请的。但是,如果你在局域网内,那就不行了,因为,同一个局域网内的计算机具有相同的公网IP(对应于网关计算机,例如192.168.0.1,172.167.0.1,10.x.x.1),你需要做一下路由器的端口映射,让别人访问服务器的每隔端口时自动转到你的计算机上。我用的是宽带路由器,不过,我不会映射关键端口,避免别人断网,我会选择一个偏僻的端口映射。这样的网络一般都具有固定的公网IP,进行了端口映射以后,访问是非常方便的咯。
那么客户端的IP怎么处理的呢?实际上,不管客户端也没有单独的公网IP,哪怕是在局域网内公用的公网IP,也是可以访问到服务器的。怎么回事呢?因为总是客户端访问服务器在先,那么服务器接到这个客户端的连接请求以后,暂时保存起来,想回复客户端时,只需要把这个连接请求包含的Socket套接字连同其中包含的IP断点信息原路返回,就达到了这个目的,于是可以推出结论:如果客户端使用局域网的话,这个服务器不可能获得客户端的内网IP。
这一点就可以解释为什么我们使用局域网连接互联网时,可以共同上网而互不影响的原因了。局域网中的计算机虽然具有共同的公网IP,但是总是客户端访问服务器在先,服务器只需要把连接请求中包含的套接字信息原路返回就可以了。
一段服务器端功能的C#实现:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
Socket ServerSocket,ClientSocket; // = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button3_Click(object sender, EventArgs e)
{
//确认设置,启动聊天进程
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse(textBox4.Text), 6251); //对方的信息
ServerSocket.Bind(iep);
ServerSocket.Listen(5); //最多发起5个连接
ServerSocket.BeginAccept(new AsyncCallback(AcceptConnection), ServerSocket); //等待接收连接
// socket.EndAccept(ar);
}
private void AcceptConnection(IAsyncResult aw)
//表示一种异步操作的状态
{
Socket server1 = (Socket)(aw.AsyncState); //服务器端
ClientSocket = server1.EndAccept(aw); //完成链接请求,得到的是客户端的套接字对象了
// 可以用client进行通信了
textBox4.Text=ClientSocket.RemoteEndPoint.ToString(); //对方的信息
ClientSocket.BeginSend(System.Text.Encoding.Unicode.GetBytes("客户你好"), 0,8, SocketFlags.None, new AsyncCallback(SendData), ClientSocket);
//使用本机的状态机
//发出的字符串
}
private void SendData(IAsyncResult aw)
{
Socket client = (Socket)aw.AsyncState;
ClientSocket.EndSend(aw); //要求完成发送,使用本
client.BeginReceive(System.Text.Encoding.Unicode.GetBytes(textBox2.Text), 0,50,SocketFlags.None, new AsyncCallback(ReceiveData), client);
//使用操作状态的状态机
//接收的位置,存储在本机上
}
private void ReceiveData(IAsyncResult aw)
{
Socket client = (Socket)aw.AsyncState;
int RecLength = client.EndReceive(aw); //接收完毕,再来启动发送
ClientSocket.BeginSend(System.Text.Encoding.Unicode.GetBytes("Hello,Another tranmitting!"),0,50, SocketFlags.None, new AsyncCallback(SendData), ClientSocket);
}
private void button4_Click(object sender, EventArgs e)
{
ServerSocket.Close();
textBox2.Enabled = false;
}
}
}
2009年3月28日星期六
订阅:
博文评论 (Atom)
0 评论:
发表评论