C#下如何实现服务器+客户端的聊天程序最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位,所以不会SOCKET是不行的。首先,本文主要是针对那些刚接触SOCKET编程的朋友,如果是高手,就可以不看此文啦,可以去陪陪老婆,比如逛街或看电视...在开始之前,我们需要预习一些基础知识:什么是SOCKET套接字?socket的英文原义是“孔”或“插座”。作为4BDSUNIX的进程通信机制,取后一种意思。通常也称作套接字,用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket正如其英文原意那样,象一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。客户软件将插头插到不同编号的插座,就可以得到不同的服务。抽象出来,socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。SOCKET连接过程根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。如何开发一个Server-Client模型的程序开发原理:服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。Socket为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。socket函数原型为:intsocket(intdomain,inttype,intprotocol);domain指明所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型:SOCK_STREAM或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值0。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上建立一个Socket意味着为一个Socket数据结构分配存储空间。Socket执行体为你管理描述符表。两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。socket在测量软件中的使用也很广泛编辑本段socket函数简介SOCKETsocket(intaf,inttype,intprotocol);应用程序调用socket函数来创建一个能够进行网络通信的套接字。第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET;第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以及协议首部);第三个参数指定应用程序所使用的通信协议。该函数如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET。套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。SOCKET通常有那几种数据格式?线程的概念?(以上基本知识我就不讲了,网上这方面资料很多的,大家找资料看下吧)我要介绍的是一个服务器端+客户端的聊天系统,程序比较简单,我先把程序运行的界面给大家看下:上面是服务器端运行界面;下面把客户端界面贴给大家看下:功能比较简单,服务器的端口号可以在“系统菜单”里面的参数配置进行修改的。看了上面的图,下面我们就给大家把代码贴出来:(因为程序比较简单,所以本人就没有去分层啦)服务器端代码:1usingSystem;2usingSystem.Collections.Generic;3usingSystem.ComponentModel;4usingSystem.Data;5usingSystem.Drawing;6usingSystem.Text;7usingSystem.Windows.Forms;89usingSystem.Net;10usingSystem.Net.Sockets;11usingSystem.Threading;12usingSystem.Xml;1314namespaceServer15{16publicpartialclassServerMain:Form17{18publicServerMain()19{20InitializeComponent();21}2223privatevoidServerMain_Load(objectsender,EventArgse)24{25this.CmdStar.Enabled=true;26this.CmdStop.Enabled=false;27}2829privatevoid配置参数ToolStripMenuItem_Click(objectsender,EventArgse)30{31SetTSet=newSet();32TSet.ShowDialog();33}3435privatevoid关于ToolStripMenuItem_Click(objectsender,EventArgse)36{37AboutTAbout=newAbout();38TAbout.Show();39}40///summary41///获得XML文件中的端口号42////summary43///returns/returns44privateintGetPort()45{46try47{48XmlDocumentTDoc=newXmlDocument();49TDoc.Load(Settings.xml);50stringTPort=TDoc.GetElementsByTagName(ServerPort)[0].InnerXml;51returnConvert.ToInt32(TPort);5253}54catch{return6600;}//默认是660055}5657//声明将要用到的类58privateIPEndPointServerInfo;//存放服务器的IP和端口信息59privateSocketServerSocket;//服务端运行的SOCKET60privateThreadServerThread;//服务端运行的线程61privateSocket[]ClientSocket;//为客户端建立的SOCKET连接62privateintClientNumb;//存放客户端数量63privatebyte[]MsgBuffer;//存放消息数据6465privatevoidCmdStar_Click(objectsender,EventArgse)66{67ServerSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);68ServerInfo=newIPEndPoint(IPAddress.Any,this.GetPort());69ServerSocket.Bind(ServerInfo);//将SOCKET接口和IP端口绑定70ServerSocket.Listen(10);//开始监听,并且挂起数为107172ClientSocket=newSocket[65535];//为客户端提供连接个数73MsgBuffer=newbyte[65535];//消息数据大小74ClientNumb=0;//数量从0开始统计7576ServerThread=newThread(RecieveAccept);//将接受客户端连接的方法委托给线程77ServerThread.Start();//线程开始运行7879CheckForIllegalCrossThreadCalls=false;//不捕获对错误线程的调用8081this.CmdStar.Enabled=false;82this.CmdStop.Enabled=true;83this.StateMsg.Text=服务正在运行+运行端口:+this.GetPort().ToString();84this.ClientList.Items.Add(服务于+DateTime.Now.ToString()+开始运行.);85}8687//接受客户端连接的方法88privatevoidRecieveAccept()89{90while(true)91{92ClientSocket[ClientNumb]=ServerSocket.Accept();93ClientSocket[ClientNumb].BeginReceive(MsgBuffer,0,MsgBuffer.Length,0,newAsyncCallback(RecieveCallBack),ClientSocket[ClientNumb]);94this.ClientList.I