private void Chat() { Byte[] bytesFromClient = new Byte[4096]; String dataFromClient; String msgTemp = null; Byte[] bytesSend = new Byte[4096]; Boolean isListen = true; while (isListen) { //try //{ if (clientSocket == null || !clientSocket.Connected) { return; } if (clientSocket.Available > 0) { Int32 len = clientSocket.Receive(bytesFromClient); if (len > -1) { dataFromClient = Encoding.UTF8.GetString(bytesFromClient, 0, len); if (!String.IsNullOrWhiteSpace(dataFromClient)) { dataFromClient = dataFromClient.Substring(0, dataFromClient.LastIndexOf("$")); //这里的dataFromClient是消息内容,上面的是用户名 if (!String.IsNullOrWhiteSpace(dataFromClient)) { //丧心病狂,只能把事件二级传出去 MessageRecieved(clNo, dataFromClient); //BroadCast.PushMessage(dataFromClient, clNo, true, clientList); Console.WriteLine(clNo + ":" + dataFromClient); } else { isListen = false; clientList.Remove(clNo); UserLoggedOut(clNo); Console.WriteLine(clNo + "已断开与服务器连接"); BroadCast.PushMessage(clNo + "已下线", "", false, clientList); clientSocket.Close(); clientSocket = null; } } } } //} //catch (Exception e) //{ // isListen = false; // clientList.Remove(clNo); // clientSocket.Close(); // clientSocket = null; // File.AppendAllText("E:\\Exception.txt",e.ToString()+"Chat"+DateTime.Now.ToString()+""); //} } }
public void StopService() { if (serverSocket != null) { BroadCast.PushMessage("Server has closed", "", false, clientList); foreach (var socket in clientList.Values) { socket.Close(); } clientList.Clear(); serverSocket.Close(); serverSocket = null; isListen = false; Log("服务停止"); } }
private void btnStop_Click(object sender, EventArgs e) { if (serverSocket != null) { serverSocket.Close(); thStartListen.Abort(); //将监听进程关掉 BroadCast.PushMessage("Server has closed", "", false, clientList); foreach (var socket in clientList.Values) { socket.Close(); } clientList.Clear(); serverSocket = null; isListen = false; Log("服务停止,断开所有客户端连接\t" + DateTime.Now.ToString()); } }
public void StartService() { if (serverSocket == null) { try { isListen = true; clientList = new Dictionary <string, Socket>(); //实例监听套接字 //参考网址:http://blog.csdn.net/sight_/article/details/8138802 //int socket(int domain, int type, int protocol); // domain: 协议域,又名协议族。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。 //协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。 // type: 指定socket类型,。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等 // protocol: 指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等 //并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议 serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //AddressFamily.InterNetwork代表IPV4地址,不包含IPV6 参考网址:http://bbs.csdn.net/topics/390283656?page=1 //端点 /* 在IPEndPoint类中有两个很有用的构造函数: * public IPEndPoint(long, int); * public IPEndPoint(IPAddress, int); * 它们的作用就是用指定的地址和端口号初始化IPEndPoint类的新实例。 * 参考网址:http://www.cnblogs.com/Medeor/p/3546359.html */ //IPAddress ipadr = IPAddress.Parse("192.168.1.100"); //如果txtIP里面有值,就选择填入的IP作为服务器IP,不填的话就默认是本机的 endPoint = new IPEndPoint(ipadr, 8080); //IPAddress.loopback是本地环回接口,其实是虚拟接口,物理不存在的 参考网址:http://baike.sogou.com/v7893363.htm?fromTitle=loopback //绑定 //把一个地址族的特定地址给socket //int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //sockfd: 即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。 //*addr: 一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同 //addrlen: 对应的是地址的长度 //通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器; //而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。 //这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。 //参考网址:http://blog.csdn.net/sight_/article/details/8138802 //但是这里的bind不是上面的bind,是.NET里面的一个bind,使 Socket 与一个本地终结点相关联。 命名空间:System.Net.Sockets 程序集:System(在 system.dll 中) //给套接字绑定一个端点,其实差不多用上面的那种bind也能实现 //参考网站: https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind(VS.80).aspx //10.127.221.248 try { serverSocket.Bind(endPoint); //设置最大连接数 //如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。 //int listen(int sockfd, int backlog); //listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。 //socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。 serverSocket.Listen(100); thStartListen = new Thread(StartListen); thStartListen.IsBackground = true; thStartListen.Start(); //这里有点不一样,原文用的是 txtMsg.Dispatcher.BeginInvoke /*Invoke在线程中等待Dispatcher调用指定方法,完成后继续下面的操作。 * BeginInvoke不必等待Dispatcher调用制定方法,直接继续下面的操作。 * 参考网址: https://zhidao.baidu.com/question/1175146013330422099.html?qbl=relate_question_1&word=Dispatcher.BeginInvoke%B5%C4%CF%E0%CD%AC%BA%AF%CA%FD * 更好的参考网址:http://www.cnblogs.com/lsgsanxiao/p/5523282.html **/ Log("网络服务启动成功"); } catch (Exception eg) { Log("服务启动失败,可能是IP地址有误"); if (serverSocket != null) { serverSocket.Close(); thStartListen.Abort(); //将监听进程关掉 BroadCast.PushMessage("Server has closed", "", false, clientList); foreach (var socket in clientList.Values) { socket.Close(); } clientList.Clear(); serverSocket = null; isListen = false; } } } catch (SocketException ex) { Log(ex.ToString()); } } }
public void BroadCastToAll(string msg) { BroadCast.PushMessage(msg + "*", "", false, clientList); }
public void BroadCastToAll(string msg) { Debug.WriteLine("广播:" + msg); BroadCast.PushMessage(msg + "*", "", false, clientList); }