Windows C语言构建网络聊天室
基于WinSock的局域网聊天室设计与实现

基于WinSock的局域网聊天室设计与实现
随着互联网的普及,人们越来越喜欢使用聊天工具来进行交流。
因此,局域网聊天室也逐渐成为了一种方便快捷的交流方式。
基于WinSock的局域网聊天室一般使用C++语言开发,这里
介绍一下它的设计与实现。
设计与实现:
1.需求分析:首先,需要明确聊天室的基本功能,例如:用户
注册登录,进入聊天室,聊天等等。
同时,也需要考虑消息的发送与接收,以及用户间的信息同步问题。
2.编程环境的选择:基于WinSock的局域网聊天室需要使用Visual Studio等开发环境来完成编码工作。
这里以Visual Studio为例,使用C++语言进行编写。
3.功能实现:将聊天室所需的所有功能以及消息发送等细节全
部完成,并通过界面的方式提供给用户使用。
同时,也需要考虑聊天室的稳定性和用户体验问题。
4.测试与优化:在完成代码编写后,需要对聊天室进行全面测试,以验证其稳定性和功能性。
针对测试中发现的问题进行优化和修复,确保聊天室的良好使用体验和用户体验。
总结:
通过基于WinSock的局域网聊天室的设计与实现,我们可以
看到,任何一款聊天室都需要从需求分析开始。
其次,还需要选择优秀的编程环境进行开发,同时也需要考虑到聊天室的各种功能需求。
在开发过程中,技术的稳定性、安全性与用户体验等问题也非常重要。
最后,测试与优化也是确保聊天室正常运行的保证。
用WINSOCK实现聊天室的VC++程序设计

用WINSOCK实现聊天室的VC++程序设计摘要:WINSOCK 是在Windows进行网络通信编程的API接口,也是Windws网络编程的事实标准。
在网络编程中最常用的方案便是客户机/服务器模型。
本文提出了在客户机/服务器模型下用WINSOCK实现Internet中常见的聊天室软件的方案。
关键词:套接字,WINSOCK,客户机/服务器,网络编程一:SOCKET简介80年代初,美国政府的高级研究工程机构(ARPA)给加利福尼亚大学Berkeley分校提供了资金,让他们在UNIX操作系统下实现TCP/IP协议。
在这个项目中,研究人员为TCP/IP网络通信开发了一个API(应用程序接口)。
这个API称为Socket接口(套接字)。
今天,SOCKET 接口是TCP/IP网络最为通用的API,也是在INTERNET上进行应用开发最为通用的API。
90年代初,由Microsoft联合了其他几家公司共同制定了一套WINDOWS下的网络编程接口,即WindowsSockets规范。
它是BerkeleySockets的重要扩充,主要是增加了一些异步函数,并增加了符合Windows消息驱动特性的网络事件异步选择机制。
WINDOWSSOCKETS规范是一套开放的、支持多种协议的Windows下的网络编程接口。
从1991年的1.0版到1995年的2.0.8版,经过不断完善并在Intel、Microsoft、Sun、SGI、Informix、Novell等公司的全力支持下,已成为Windows网络编程的事实上的标准。
目前,在实际应用中的WINDOWSSOKCETS 规范主要有1.1版和2.0版。
两者的最重要区别是1.1版只支持TCP/IP协议,而2.0版可以支持多协议。
2.0版有良好的向后兼容性,任何使用1.1版的源代码,二进制文件,应用程序都可以不加修改地在2.0规范下使用。
SOCKET实际在计算机中提供了一个通信端口,可以通过这个端口与任何一个具有SOCKET 接口的计算机通信。
c的聊天室

一、服务器/客户端聊天室模型聊天室客户端(商用PC)服务器聊天室客户端(其他)聊天室客户端(笔记本)其他服务器1.首先启动聊天室服务器,使得TcpListener开始监听端口,此时TcpListener会进入Pending状态,等待客户端连接;2.其次,当有客户端连接后,通过AccepSocket返回与客户端连接的Socket 对象,然后通过读写Socket对象完成与聊天室客户端的数据传输。
聊天室客户端成功启动后,首先创建一个Socket对象,然后通过这个Socket 对象连接聊天室服务器,连接成功后开通Socket完成数据的接收和发送处理。
二、系统功能设计本设计为一个简单的聊天室工具,设计基本的聊天功能,如聊天、列表维护等。
系统主要为两大块:聊天室服务器及聊天室客户端。
服务器界面设计如下:客户端界面设计如下:三、聊天协议的应答A—网络—B主机与主机通信主要识别身份(标识设备用IP)及通信协议网络应用程序——端口号——接收数据注:地址是总机,端口号是分机(传输层)2.端口号为16位二进制数,范围0到65535,但实际编程只能用1024以上端口号Socket编程首先,我们了解常用网络编程协议。
我们用得最多的协议是UDP和TCP,UDP是不可靠传输服务,TCP是可靠传输服务。
UDP就像点对点的数据传输一样,发送者把数据打包,包上有收信者的地址和其他必要信息,至于收信者能不能收到,UDP协议并不保证。
而TCP协议就像(实际他们是一个层次的网络协议)是建立在UDP的基础上,加入了校验和重传等复杂的机制来保证数据可靠的传达到收信者。
一个是面向连接一个无连接,各有用处,在一些数据传输率高的场合如视频会议倾向于UDP,而对一些数据安全要求高的地方如下载文件就倾向于TCP。
Socket————网络应用程序电话机————访问通信协议聊天协议的应答:聊天状态:CLOSED和CONNECTED状态执行CONN命令后进入CONNECTED状态,执行下列命令:CONN:连接聊天室服务器JOIN:加入聊天(通知其他用户本人已经加入聊天室服务器)LIST:列出所有的用户(向客户端发送全部的登录用户名字)CHAT:发送聊天信息(公开的聊天信息)PRIV:进行私聊(三个参数:私聊信息用户;接收私聊信息用户;发送信息)EXIT:客户端向服务器发送离开请求;QUIT:退出聊天,服务器向客户端发送退出命令(执行QUIT命令聊天状态变为CLOSED)四、系统实现服务器协议解析:当有客户端连接聊天室服务器后,服务器立刻为这个客户建立一个数据接收的线程(多用户程序必备)。
C语言实现简易网络聊天室

C语⾔实现简易⽹络聊天室本⽂实例为⼤家分享了C语⾔实现⽹络聊天室的具体代码,供⼤家参考,具体内容如下业务逻辑:1、客户端注册名字2、告诉所有在线的客户端,XXX进⼊聊天室3、新建⼀个线程为该客户端服务,随时接收客户端发送来的消息4、当接收到⼀个客户端的消息时,向每⼀个客户端转发⼀份(群聊)5、同时在线⼈数最多50⼈任何客户端可以随意随时进⼊或退出客户端服务端代码server.c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#include <pthread.h>#include <semaphore.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#ifndef DEBUG#define debug(format,...) {}#else#define debug(format,...) \{\fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\fprintf(stdout,format,##__VA_ARGS__);\fprintf(stdout,"\n");\}#endif//DEBUG#define error(format,...)\{\fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\fprintf(stdout,format,##__VA_ARGS__);\fprintf(stdout,":%m\n");\exit(EXIT_FAILURE);\}// 客户端最⼤连接数#define CLIENT_MAX 50// 服务器端⼝号#define PORT 5566// 缓冲区⼤⼩#define BUF_SIZE 4096// 重定义socket地址类型typedef struct sockaddr* SP;// 客户端结构体typedef struct Client{int sock;//socket 标识符pthread_t tid; //线程IDchar name[20];struct sockaddr_in addr;}Client;// 定义50个存储客户端的结构变量Client clients[50];// 定义信号量⽤于限制客户端的数量sem_t sem;// 信号处理函数void sigint(int num){for(int i=0; i<10; i++){if(clients[i].sock){pthread_cancel(clients[i].tid);//销毁线程}}debug("服务器退出!");exit(EXIT_SUCCESS);}void client_eixt(Client* client){sem_post(&sem);close(client->sock);client->sock = 0;}void client_send(Client* client,char* buf){size_t len = strlen(buf)+1;for(int i=0; i<CLIENT_MAX; i++){if(clients[i].sock && clients[i].sock != client->sock) {send(clients[i].sock,buf,len,0);}}}void* run(void* arg){Client* client = arg;char buf[BUF_SIZE] = {};// 接收昵称int ret_size = recv(client->sock,client->name,20,0); if(0 >= ret_size){client_eixt(client);return NULL;}// 通知其它客户端新⼈上线sprintf(buf,"欢迎%s进⼊聊天室",client->name); client_send(client,buf);for(;;){// 接收消息ret_size = recv(client->sock,buf,BUF_SIZE,0);if(0 >= ret_size || 0 == strcmp("quit",buf)){// 通知其它客户端退出sprintf(buf,"%s退出聊天室",client->name);client_send(client,buf);client_eixt(client);return NULL;}strcat(buf,":");strcat(buf,client->name);client_send(client,buf);debug(buf);}}int main(int argc,const char* argv[]){signal(SIGINT,sigint);debug("注册信号处理函数成功!");sem_init(&sem,0,CLIENT_MAX);debug("初始化信号量成功!");int svr_sock = socket(AF_INET,SOCK_STREAM,0);if(0 > svr_sock){error("socket");}debug("创建socket对象成功!");struct sockaddr_in svr_addr = {};svr_addr.sin_family = AF_INET;svr_addr.sin_port = htons(PORT);svr_addr.sin_addr.s_addr = INADDR_ANY;socklen_t addrlen = sizeof(svr_addr);debug("准备通信地址成功!");if(bind(svr_sock,(SP)&svr_addr,addrlen)){error("bind");}debug("绑定socket对象和通信地址成功!");if(listen(svr_sock,10)){error("listen");}debug("设置监听socket监听成功!");for(;;){debug("等待客户端连接...");sem_wait(&sem);int index = 0;while(clients[index].sock){index++;}clients[index].sock = accept(svr_sock,(SP)&clients[index].addr,&addrlen);if(0 > clients[index].sock){kill(getpid(),SIGINT);}debug("有新的客户端连接,from ip:%s",inet_ntoa(clients[index].addr.sin_addr)); pthread_create(&clients[index].tid,NULL,run,&clients[index]);}}客户端代码client.c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#include <pthread.h>#include <semaphore.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#ifndef DEBUG#define debug(format,...) {}#else#define debug(format,...) \{\fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\fprintf(stdout,format,##__VA_ARGS__);\fprintf(stdout,"\n");\}#endif//DEBUG#define error(format,...)\{\fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\fprintf(stdout,format,##__VA_ARGS__);\fprintf(stdout,":%m\n");\exit(EXIT_FAILURE);\}#define BUF_SIZE 4096#define SERVER_PORT 5566#define SERVER_IP "192.168.0.125"typedef struct sockaddr* SP;void* run(void* arg){int cli_sock = *(int*)arg;char buf[BUF_SIZE] = {};for(;;){int ret_size = recv(cli_sock,buf,BUF_SIZE,0);if(0 >= ret_size){printf("服务器正在升级,请稍候登录!\n");exit(EXIT_SUCCESS);}printf("\r%30s\n>>>",buf);fflush(stdout);}}int main(int argc,const char* argv[]){int cli_sock = socket(AF_INET,SOCK_STREAM,0);if(0 > cli_sock){error("socket");}struct sockaddr_in cli_addr = {};cli_addr.sin_family = AF_INET;cli_addr.sin_port = htons(SERVER_PORT);cli_addr.sin_addr.s_addr = inet_addr(SERVER_IP);socklen_t addrlen = sizeof(cli_addr);if(connect(cli_sock,(SP)&cli_addr,addrlen)){printf("服务器正在升级,请稍候登录!\n");return EXIT_SUCCESS;}char buf[BUF_SIZE] = {};printf("请输⼊你的眤称:");gets(buf);send(cli_sock,buf,strlen(buf)+1,0);pthread_t tid;pthread_create(&tid,NULL,run,&cli_sock);for(;;){printf(">>>");gets(buf);send(cli_sock,buf,strlen(buf)+1,0);if(0 == strcmp("quit",buf)){printf("退出聊天室!\n");return EXIT_SUCCESS;}}}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
C语言实现简易聊天室

通信流程了解完了⼀个 socket 的基本步骤后我们了解⼀下多线程以及线程的同步。
线程的同步每个线程都可以访问进程中的公共变量,资源,所以「使⽤多线程的过程中需要注意的问题是如何防⽌两个或两个以上的线程同时访问同⼀个数据,以免破坏数据的完整性」。
数据之间的相互制约包括1、「直接制约关系」,即⼀个线程的处理结果,为另⼀个线程的输⼊,因此线程之间直接制约着,这种关系可以称之为同步关系2、「间接制约关系」,即两个线程需要访问同⼀资源,该资源在同⼀时刻只能被⼀个线程访问,这种关系称之为线程间对资源的互斥访问,某种意义上说互斥是⼀种制约关系更⼩的同步windows线程间的同步⽅式有四种:「临界区、互斥量、信号量、事件。
」本项⽬是基于事件内核对象实现的线程同步,事件内核对象是⼀种抽象的对象,有受信和未授信两种状态,通过等待WaitForSingleObject实现线程同步。
事件内核对象的使⽤流程如下:「创建事件内核对象」HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性 BOOL bManualReset, //是否⼿动重置事件对象为未受信对象 BOOL bInitialState, //指定事件对象创建时的初始状态 LPCSTR lpName //事件对象的名称);「设置内核对象状态」BOOL SetEvent( HANDLE hEvent /*设置事件内核对象受信*/);BOOL ResetEvent( HANDLE hEvent /*设置事件内核对象未受信*/);「堵塞等待事件内核对象直到事件内核对象的状态为受信」DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds);具体使⽤阅读全⽂在我的个⼈⽹站⾥看,篇幅太多。
服务端设计在创建套接字绑定监听之后会有⼀个等待连接的过程,在接收到新连接之后,需要创建⼀个线程来处理新连接,当有多个新连接时可通过创建多个线程来处理新连接,「定义最⼤连接数量以及最⼤套接字和最⼤线程」#define MAX_CLNT 256int clnt_cnt = 0; //统计套接字int clnt_socks[MAX_CLNT]; //管理套接字HANDLE hThread[MAX_CLNT]; //管理线程「当有新连接来临的时候创建线程处理新连接」,并将新连接添加到套接字数组⾥⾯管理hThread[clnt_cnt] = CreateThread(NULL, // 默认安全属性NULL, // 默认堆栈⼤⼩ThreadProc, // 线程⼊⼝地址(执⾏线程的函数)(void*)&clnt_sock, // 传给函数的参数0, // 指定线程⽴即运⾏&dwThreadId); // 返回线程的ID号clnt_socks[clnt_cnt++] = clnt_sock;线程的处理函数ThreadProc不做过多讲解,⼤致就是「⼀个服务器,多个客户端进⾏数据的接收以及群发」。
C语言编写网络聊天工具

C语言编写网络聊天工具C语言作为一种高效、灵活的编程语言,在网络聊天工具的开发中扮演着重要的角色。
本文将介绍如何使用C语言编写一个简单的网络聊天工具,并着重讨论实时通信、消息传递和用户界面设计等方面的问题。
1. 引言在当今社交化的时代,网络聊天工具的需求日益增长。
通过网络聊天工具,人们可以方便地与他人进行沟通和交流,促进社会、工作和学习等各个方面的发展。
而C语言作为一种经典的编程语言,其能够提供高效的性能和灵活的功能,非常适合用于网络聊天工具的开发。
2. 网络编程基础在开始编写网络聊天工具之前,我们首先需要了解一些网络编程的基础知识。
C语言提供了一系列的库函数来实现网络编程功能,例如socket、bind、listen等等。
通过这些函数,我们可以建立服务器和客户端之间的通信连接,实现消息的传递和数据的交换。
3. 实时通信实时通信是网络聊天工具的核心功能之一。
在C语言中,我们可以使用套接字(socket)来实现实时通信。
服务器和客户端之间可以通过套接字进行连接,通过send和recv函数进行消息的发送和接收。
在实现实时通信时,我们需要考虑消息的封装和解析、连接的建立和维护、错误处理等方面的问题。
4. 用户界面设计用户界面设计是网络聊天工具的另一个重要方面。
通过一个友好、直观的用户界面,用户可以方便地进行操作和进行聊天。
在C语言中,我们可以使用图形库(如GTK+或Qt)或者命令行界面来实现用户界面。
不同的界面设计方案有不同的特点和适用场景,开发者可以根据实际需求选择合适的方案。
5. 消息传递在网络聊天工具中,消息的传递是至关重要的。
C语言提供了丰富的数据结构和函数来进行消息的封装和解析。
我们可以定义一个消息结构体,包含发送者、接收者、时间戳、内容等属性,通过函数进行消息的打包和解包。
同时,我们还可以使用消息队列、线程或者信号量等技术来实现多线程处理,提高并发性能。
6. 安全性和保密性在网络聊天工具的开发中,安全性和保密性是非常重要的考虑因素。
VC基于TCP和UDP的聊天室建立详细介绍

基本任务VC TCP和UDP通信编程语言:Visual C++语言版本:Visual C++ 6.0至Visual 2008实施参考:略任务目标:建立一个VC程序,实施TCP和UDP通信。
实施提示:略任务要求:1、编写两个VC程序,完成以下功能:●一个程序为服务端,建立TCP服务端套接字。
●另外一个程序为客户端,建立TCP客户端套接字。
●这两个程序可以互联,完成一个基于TCP/IP网络的文本聊天程序。
首先,新建一个工程用来编写服务端,具体步骤是新建工程win32控制台程序工程名为PRJ1srv,然后文件新建文件C++源文件,文件名为TCPsrv。
然后在此文件中添加如下代码:#include <winsock2.h>#include <stdio.h>//=========基于TCP聊天程序=====//服务器端void main(){//加载WinSock库//定义一个WORD类型的变量WORD wVersionRequested;WSADATA wsaData;int err;//使用MAKEWORD的宏去请求一个1.1版本的WinSockwVersionRequested = MAKEWORD( 1, 1 );err = WSAStartup( wVersionRequested, &wsaData );if ( err != 0 ) {//如果返回值不等于0,程序退出return;}//判断一下返回的版本号低位值和高位值if ( LOBYTE( wsaData.wVersion ) != 1 ||HIBYTE( wsaData.wVersion ) != 1 ) {//如果不是请求的winsock版本,程序调用WSACleanup函数终//止对winsock库的使用,然后返回WSACleanup( );return;}//创建socket//创建流式套接字,基于TCP(SOCK_STREAM)SOCKET socSrv = socket(AF_INET, SOCK_STREAM, 0);//Socket地址结构体的创建SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//转换Unsigned long 型为网络字节序格式addrSrv.sin_family = AF_INET;//指定地址簇addrSrv.sin_port = htons(6000);//指定端口号,除sin_family参数外,其它参数都是网络字节序,因此需要转换//将套接字绑定到一个端口号和本地地址上bind(socSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));//设置监听的最大连接数为5listen(socSrv, 5);char sendBuf[100];//发送信息char recvBuf[100];//接收信息char tempBuf[100];//存放中间数据//定义用来接收客户端Socket的结构体SOCKADDR_IN addrClient;int len = sizeof(SOCKADDR);//循环等待接受客户端发送请求while (1){SOCKET sockConn = accept(socSrv, (SOCKADDR*)&addrClient, &len);//接收数据recv(sockConn, tempBuf, 100, 0);if ('q' != tempBuf[0]){//如果不是q,表示是收到的数据sprintf(recvBuf, "%s say: %s", inet_ntoa(addrClient.sin_addr), tempBuf);//打印输出printf("%s\n", recvBuf);printf("please input your data:\n");//获取数据,得到一行数据gets(sendBuf);//发送数据send(sockConn, sendBuf, strlen(sendBuf) + 1,0);}else{//如果是q,表示要退出,发送一个qprintf("%s request to quit the chat platform", inet_ntoa(addrClient.sin_addr));send(sockConn, "q", strlen("q") + 1, 0);break;}}closesocket(socSrv);WSACleanup();}在使用之前须链接库函数:工程->设置->Link->输入ws2_32.lib。
VC做的聊天室项目设计

田鸡聊天器一、登陆问题用户登陆时只用其用户ID(即妮称),QQ号对用户不透明。
二、数据库设计1.用户列表User.db该数据库主要存储本机上的用户ID和密码字段设计:字段名类型长度说明ID Integer 12 QQ号码Username String 20 用户名(即妮称)Password String 16 密码Memo Memo 备注2.好友信息Friends.db该数据库主要存储用户好友的相关信息字段设计:字段名类型长度说明ID Integer 12 QQ号码Username String 20 用户名(即妮称)FaceID Integer 100 用户头像序列IsBaddy Boolean 是否被列入黑名单Memo Memo 备注3.聊天记录ChatLog.db存储与好友之间的聊天记录字段名类型长度说明ID Integer 12 QQ号码Username String 20 用户名(即妮称)Sender Boolean 消息发送者Time DataTime 消息发送时间Msg Memo 消息内容Memo Memo 备注4.系统消息SystemMsg.db字段名类型长度说明ID 自动增值主关键字Time DataTime 发送时间Msg Memo 消息内容Memo Memo 备注三、通讯协议1.统一规定2.具体协议内容①SYS(系统信息)格式:SYS*XXXX(xxxx为消息的具体内容)*②ONL(用户上线)格式:ONL*QQNumber*NickName*001*(第二位为QQ号,第三位为“妮称”,第四位为“头像”ID)③OFF(用户下线)格式:OFF*QQNumber*④LEA(用户离开)格式:LEA*QQNumber*⑤HID(隐身)格式:HID*QQNumber*⑥MSG(正常信息)格式:MSG*QQNumber*NickName*001*XXXXXXX*⑦IMO(I am online报告“我在线”)格式:IMO*QQNumber*⑧FIN(Find friends查找好友)格式:FIN*⑨YFM (You find me 你找到我啦) 收到FIN后,返回此信息格式: YFM*sQQNumber*sUserName*iFaceID*四.程序主要模块1.主要处理函数、过程①function SysMsg(s:string):Boolean;(系统消息)A)显示消息内容B)存储消息内容②function Online(s:string):Boolean;(用户上线)A)将消息分离成三份,存储在三组数组Msg中B)在数据库中对照QQNumber,是否有此好友,若有则先判断好友是否更改其个人信息,更改则更新数据库后添加好友图标;若无,不作处理。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
m_addr.sin_addr.S_un.S_un_w.s_w1=(168<<8)|192;
m_addr.sin_addr.S_un.S_un_w.s_w2=(1<<8)|0;
方法3:
m_addr.sin_addr.S_un.S_addr=(1<<24)|(0<<16)|(168<<8)|192;
为了更方便地赋值,winsock还为我们提供了一个函数inet_addr(),可以把用字符串表示的IP地址“192.168.0.1”直接赋给结构体m_addr:
flags<输入>:一般取0。
from、fromlen/to、tolen<输入>:含义和用法与bind()中的相同,分别表示接收和发送数据的对象。
5.Closesocket():
【函数原型】
int closesocket ( SOCKET s);
【使用说明】
和关闭文件操作一样,socketd在使用以后,也要关闭。
IP地址sin_addr结构定义如下:
struct in_addr
{
union
{
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
};
这样,对于一个IP地址,例如“192.168.0.1”,你可以用以下三种方法赋给一个sockaddr结构体(例如struct sockaddr_in m_addr;):
作为网络编程接口,Winsock屏蔽了网络底层的复杂的协议和数据结构,使得编程人员对网络的操作变得非常简单,因此,在Win32平台上,访问众多的基层网络协议,Winsock是首选接口。
用Winsock构建一个网络聊天室,有两种基本的方式:数据报方式和流方式。
一、面向无连接的数据报方式
数据报方式又称无连接方式,对应的是UDP(User Datagram Protocol)协议。这种方式不提供数据无错保证,数据可能丢失或重复并且接收顺序混乱,后发出的报文可能会先收到,并且报文的长度是有限制的;不过,由于取消了重发校验机制,能够达到较高的通信速率,可以用于对数据可靠性要求不高的通信,如实时的语音、图像传送和广播消息等。
这种方式主要使用了以下几个函数:
1.Connect():
【函数原型】
int connect ( SOCKET s, const struct sockaddr FAR* name, int namelen);
【使用说明】
与通信对象建立连接,主要用在客户端。其中s、name和namelen的含义与使用方法和bind()相同。如果连接失败,该函数会返回SOCKET_ERROR。
2.listen():
【函数原型】
int listen (SOCKET s,int backlog);
【使用说明】
对于服务器端程序,当申请到Socket,并指定通信对象为INADDR_ANY之后,就应该等待一个客户端程序的连接。当没有连接请求时,就进入等待状态,直至有一个请求到达为止。其中:
s<输入>:是socket()创建的socket。
int FAR* fromlen );
int sendto (SOCKET s,const char FAR * buf, int len, int flags,const struct sockaddr FAR * to,
int tolen);
【使用说明】
s<输入>:是连接用的socket。
buf、len<输入>:发送或接收的数据包字符串的地址和长度。
backlog<输入>:等待连接的队列长度,可取1~5。如果当某个客户程序要求连接之时,服务器已与其他客户程序连接,则后来的连接请求会被放在队列中,等待服务器空闲的时候再与之连接。当队列达到指定长度(backlog的值)时,再来的连接请求都将被拒绝。
3.accept():
【函数原型】
SOCKET accept (SOCKET s,struct sockaddr FAR* addr,int FAR* addrlen);
图1面向无连接的数据报方式流程图
可以为服务器端和客户端分别建立如图1、图2所示对话框:
图1服务器端图2客户端
相应的源程序见附件中的源程序Chat_Room1。
二、面向连接的流方式
流方式又称无连接方式,对应的是TCP(Transport Control Protocol))协议。在这种方式下,两个通信的应用程序之间先要建立一种连接链路,确定了这条链路之后,数据才能被正确接收和发送。流方式的特点是通信可靠,对数据有校验和重发的机制,通常用来做数据文件的传输如FTP、Telnet等。
方法_un_b.s_b1=192;
m_addr.sin_addr.S_un.S_un_b.s_b2=168;
m_addr.sin_addr.S_un.S_un_b.s_b3=0;
m_addr.sin_addr.S_un.S_un_b.s_b4=1;
方法2:
和C语言一样,函数是Windows C编程的最基本的单位。不过,Windows C主要使用API函数,而网络编程则主要使用Winsock提供的API函数。数据方式构建网络聊天室主要使用了以下几个函数:
1.WSAStartup():初始化。
【函数原型】
int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
3.Bind():为创建Socket指定通信对象。
【函数原型】
int bind ( SOCKET s, const struct sockaddr FAR* name, int namelen );
【使用说明】
成功创建了Socket之后,就应该选定通信的对象。首先是自己的程序要与网上的哪台计算机通话;其次,在多任务的系统下,该台计算机上可能会有几个程序在工作,必须指出要与哪个程序通信。前者可以通过IP地址来确定,而后者则由端口号来确定的。一台计算机有65536个端
LpWSAData<输出>:是一个指向WSADATA资料的指针。这个资料我们一般不使用。
2.Socket():创建一个Socket。
【函数原型】
SOCKETsocket(int af,int type,int proctocol);
【使用说明】
Winsock网络通信的第一步通常就是调用这个函数。所有的通信在建立之前都有要创建一个Socket。该函数的功能与文件操作中的fopen()类似,返回值是由Winsock定义的一种数据类型SOCKET,它实际是一个整型数据,是Socket创建成功时,Windows分配给程序的Socket编号,后面调用传输函数时,可以把它像文件指针样引用。如果Socket建立失败,返回值WIVALID_SOCKET。
Windows C语言构建网络聊天室
利用C语言编写Windows应用程序有两种方式:一种是WindowsC编程方式,另一种是VisualC++编程方式。在一般情况下,VisualC++编程方式编写的程序源代码量小、开发时的工作量小、工作难度也较小,但编译后的代码量较大,运行速度略低;而WindowsC编程方式编写的程序源代码量虽然较大,但可执行代码效率高。随着技术的进步,VisualC++编程方式已被广泛采用,但象网络编程等一些对速度要求高、对硬件操作较多的程序,大多数还是用WindowsC编程方式开发的。另外,学习Windows C程序设计,还有助于更深入地了解Windows的内幕和Windows API。
char * IP_String=”192.168.0.1”;
m_addr.sin_addr.S_un.S_addr=inet_addr(IP_String);
4.recvfrom()/sendto():
【函数原型】
int recvfrom ( SOCKET s,char FAR* buf, int len,int flags,struct sockaddr FAR* from,
Af<输入>:指address family(地址族),一般都填AF_INET,表示是在Internet上的Socket;
Type<输入>::是Socket的类型,当采用流连接方式时,用SOCK_STREAM;采用数据报文方式时,用SOCK_DGRAM。
Proctocol<输入>:一般都有为0,表示对两种类型的Socket分别采用缺省的TCP和UDP传输协议。
Internet上的聊天室程序一般都是Client/Server结构的,由服务器提供服务端连接响应,使用者通过客户端程序登录到服务器(面向接连的流方式),或直接向服务端发送报文(面向无连接的数据报方式)。相应地,聊天室程序也就分为服务器端和客户端两部分。
面向无连接的数据报方式的程序流程图如图1所示:
【使用说明】
每一个使用winsock的应用程序,都必须进行WSAStart函数调用,并且只有在调用成功之后才能使用其它的winsock网络操作函数。
返回值:调用成功返回0;否则,返回出错信息。