C语言用UDP 实现局域网聊天程序源码

合集下载

见习无聊写的一个基于c# socket udp的简单的局域网聊天软件 含源码

见习无聊写的一个基于c# socket udp的简单的局域网聊天软件 含源码

见习无聊写的一个基于c# socket udp的简单的局域网聊天软件含源码实习无聊,写的一个基于c# socket udp的简单的局域网聊天软件含源码最后在公司实习,新人不给活干,就自己随便看看,了解一些DevExpress控件啊,编码规范啊之类的,自己就寻思着写一点点小东西练习练习出于自己对c# socket这块不熟,就选择了这块,顺便可以进一步了解委托代理。

闲话不说,先说下这次做的东西:一个局域网聊天的小软件主要基于udp的通信,如果读者还不知道udp or tcp 那请度娘一下。

直接看图吧:本机端局域网中的另一端猛击我去我的博客查看此软件的详解再猛击我去免费下载源码在软件上设计的不到之处或者源码上编写的问题之处请大家留言发帖指导啊------解决方案--------------------------------------------------------看看...------解决方案--------------------------------------------------------感觉还是不错的、。

美化美化就更好了------解决方案--------------------------------------------------------最后在公司实习,新人不给活干,就自己下载下来看看。

------解决方案--------------------------------------------------------------解决方案--------------------------------------------------------能p2p聊天不,------解决方案--------------------------------------------------------------解决方案--------------------------------------------------------------解决方案--------------------------------------------------------也学习一下吧!------解决方案--------------------------------------------------------来虚心学习------解决方案--------------------------------------------------------好好干,有前途------解决方案--------------------------------------------------------支持一下------解决方案--------------------------------------------------------还真不错! GUI做得挺像那么回事的------解决方案--------------------------------------------------------感觉还不错哦~同是新人,加油哦!------解决方案--------------------------------------------------------学习了。

C++基于socketUDP网络编程实现简单聊天室功能

C++基于socketUDP网络编程实现简单聊天室功能

C++基于socketUDP⽹络编程实现简单聊天室功能本⽂实例为⼤家分享了C++基于socket UDP实现简单聊天室功能的具体代码,供⼤家参考,具体内容如下0.通信步骤流程图(左:服务器;右:客户端;)1.服务器代码1.1服务器类头⽂件(CServer_UDP.h)#pragma once#include <winsock2.h>class CServer_UDP{public:CServer_UDP();void SendMsg(const char sendBuf[]);void RecMsg();~CServer_UDP();private:SOCKET m_sServer;struct sockaddr_in m_SocAddrClient; //建⽴连接时,⽤于保存客户端信息bool m_terminal;};1.2服务器类源⽂件(CServer_UDP.cpp)#define _WINSOCK_DEPRECATED_NO_WARNINGS#include "CServer_UDP.h"#include <iostream>#pragma comment(lib, "ws2_32.lib")CServer_UDP::CServer_UDP():m_terminal(false){//必须进⾏如下初始化,否则socket()会返回10093错误//初始化WSAWORD sockVersion = MAKEWORD(2, 2);WSADATA wsaData;if (WSAStartup(sockVersion, &wsaData) != 0) //通过⼀个进程初始化ws2_32.dll{std::cout << "Initialize WSA failed" << std::endl;return;}//初始化UDDP套接字m_sServer = socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in m_SocAddrserver;m_SocAddrserver.sin_addr.S_un.S_addr = 0;//htonl(INADDR_ANY);m_SocAddrserver.sin_family = AF_INET;m_SocAddrserver.sin_port = htons(8090);int ret = bind(m_sServer, (sockaddr*)&m_SocAddrserver, sizeof(m_SocAddrserver));if (ret == -1){std::cout << "bind failed!" << std::endl;WSACleanup();}else{//此处必须赋初值,不然会导致服务器端⽆法正常发送int len_Client = sizeof(sockaddr);char recBuf[1025];int len = recvfrom(m_sServer, recBuf, 1024, 0, (sockaddr*)&m_SocAddrClient, &len_Client);if (len > 0){recBuf[len] = '\0';std::cout << "Client say:" << recBuf << std::endl;}}}void CServer_UDP::SendMsg(const char sendBuf[]){int ret = sendto(m_sServer, sendBuf, strlen(sendBuf), 0, (sockaddr*)&m_SocAddrClient, sizeof(m_SocAddrClient)); if (ret == -1){std::cout << "send failed" << std::endl;std::cout << GetLastError()<< std::endl;}}void CServer_UDP::RecMsg(){char recBuf[1025];while (!m_terminal){//std::cout << "Begin rec...(server)" << std::endl;int len = recvfrom(m_sServer, recBuf, 1024, 0, 0, 0);if (len > 0){recBuf[len] = '\0';std::cout << "Client say:" << recBuf << std::endl;}}}CServer_UDP::~CServer_UDP(){closesocket(m_sServer);WSACleanup();}1.3服务器主函数#include <iostream>#include <thread>#include <string>#include "CServer_UDP.h"using namespace std;int main(){CServer_UDP server_UDP;thread recProc(&CServer_UDP::RecMsg, &server_UDP);while (1){//cout << "Pleaes input content:" << endl;string content;cin >> content;server_UDP.SendMsg(content.c_str());}recProc.join();cout << "I love china!" << endl;system("pause");return 0;}2.客户端代码2.1客户端类头⽂件(CClient.h)#pragma once#include <winsock2.h>class CClient{public:CClient();void RecMsg();void SendMsg(const char sendBuf[]);~CClient();private:SOCKET m_sockClient;sockaddr_in m_TargetServer;};2.2客户端类源⽂件(CClient.cpp)#define _WINSOCK_DEPRECATED_NO_WARNINGS#include "CClient.h"#include <iostream>#pragma comment(lib, "ws2_32.lib")CClient::CClient(){//必须进⾏如下初始化,否则socket()会返回10093错误//初始化WSAWORD sockVersion = MAKEWORD(2, 2);WSADATA wsaData;if (WSAStartup(sockVersion, &wsaData) != 0) //通过⼀个进程初始化ws2_32.dll{std::cout << "Initialize WSA failed" << std::endl;return;}m_sockClient = socket(AF_INET, SOCK_DGRAM, 0);m_TargetServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");m_TargetServer.sin_family = AF_INET;m_TargetServer.sin_port = htons(8090);if (m_sockClient == -1){std::cout << "Create socket failed!" << std::endl;WSACleanup();}else{//发送信息与服务器建⽴连接(必须加)sendto(m_sockClient, "hello server", strlen("hello server"), 0, (sockaddr*)&m_TargetServer, sizeof(m_TargetServer)); }}void CClient::SendMsg(const char sendBuf[]){sendto(m_sockClient, sendBuf, strlen(sendBuf), 0, (sockaddr*)&m_TargetServer, sizeof(m_TargetServer));}void CClient::RecMsg(){char recBuf[1025];while (1){//std::cout << "Begin rec...(client)" << std::endl;int len = recvfrom(m_sockClient, recBuf, 1024, 0, 0, 0);if (len > 0){recBuf[len] = '\0';std::cout << "Server say: " << recBuf << std::endl;}}}CClient::~CClient(){closesocket(m_sockClient);WSACleanup();}2.3客户端主函数#include <iostream>#include <string>#include <thread>#include "CClient.h"using namespace std;int main(){CClient client_UDP;thread RecProc(&CClient::RecMsg, &client_UDP); while (1){//cout << "Please input content:" << endl;string content;cin >> content;client_UDP.SendMsg(content.c_str());}RecProc.join();cout << "I love china!" << endl;system("pause");return 0;}3.效果图(win7+VS2017)3.1服务端3.2客户端以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

用C开发局域网聊天工具

用C开发局域网聊天工具

用Socket开发局域网聊天工具(C#)程序设计成为简单的服务端和客户端之间的通信,但通过一些方法可以将这两者进行统一起来,让服务端也成为客户端,让客户端也成为服务端,使它们之间可以互相随时不间断的通信.考虑到实现最原始的服务端和客户端之间的通信所需要的步骤对于写这样的程序是很有帮助的.作为服务端,要声明一个SocketA并绑定(Bind)某一个IP+这个IP指定的通信端口,比如这个是127.0.0.1:9050,然后开始监听(Listen), Listen可以监听来自多个IP传过来的连接请求,具体可以同时连接几个客户端,Listen方法中可以设定一个参数.如果Listen到某一个客户端发来连接请求了,这时定义一个新的SocketB专门负责与这个客户端的通信,SocketB=A.Accept().这时可以获取这个客户端的IP和端口, IPEndPoint C =(IPEndPoint)B.RemoteEndPoint, C.Address和C.Port分别表示客户端C的IP地址和端口.这时通过B.Send()方法就可以给C发送消息了,B.Receive()可以接收客户端C发来的信息.作为客户端,也需要声明一个Socket D并绑定某一个IP+本机一个未被占用的端口,定义IPEndPointE表示要进行连接的服务端Socket,要指明E的IP和端口,这样才可以进行端口对端口之间的通信,接下来就可以尝试D.Connect(E),连接成功之后就可以发送和接收数据了,D.Send(),D.Receive.发送消息时,数据都是以字节或字节数组为单位进行传输的,比如我客户端D要发送"Hello World"则要这样写:D.Send(Encoding.ASCII.GetBytes("Hello World")).接受消息时,也是以字节或字节数组,比如服务端要接受D刚才发送的Hello World,可以这样写:Byte[] data = new Byte[1024]; int receivedDataLength = B.Receive(data);string stringdata = Encoding.ASCII.GetString(data, 0,receivedDataLength); stringdata这时就是Hello World.上面只是大概的阐述了服务端与客户端之间的通信过程,在网上找到了具体的代码例子,也贴过来参考参考.这个例子没有将服务端与客户端统一起来,他是分别写服务端和客户端的.服务端:using System;using System;using ;using .Sockets;using System.Text;namespace tcpserver{/// <summary>/// Class1的摘要说明。

C#使用UDP Client编写聊天程序

C#使用UDP Client编写聊天程序

★C#使用UDP Client编写聊天程序UDPClient 类使用UDP 与网络服务通讯。

UDP 的优点是简单易用,并且能够同时向多个地址广播消息。

但由于UDP 协议是一个无连接协议,因此发送到远程终结点的UDP 数据文报不一定能够到达,也不一定能够以发送的相同顺序到达。

使用UDP 的应用程序必须准备处理丢失的和顺序有误的数据文报。

若要使用UDP 发送数据文报,必须知道承载所需服务的网络设备的网络地址以及该服务用于通讯的UDP 端口号。

特殊网络地址用于支持基于IP 的网络上的UDP 广播消息。

下面探讨的内容以Internet 上使用的IP 版本4 地址族作为示例。

IP 版本4 地址使用32 位指定网络地址。

对于使用255.255.255.0 网络掩码的C 类地址,这些位被分为四个八位字节。

当以十进制数表示时,这四个八位字节构成熟悉的以点分隔的四部分表示法,如192.168.100.2。

前两个八位字节(此示例中为192.168)构成网络号;第三个八位字节(100) 定义子网;最后一个八位字节(2) 是主机标识符。

将IP 地址的所有位均设置为1(即255.255.255.255)可构成有限的广播地址。

将UDP 数据文报发送到此地址可将消息传递到该广播网络上的任何主机。

由于路由器从不转发发送到此地址的消息,因此只有已连接的网络上的主机才可看到这些广播。

通过将部分地址的所有位全都设置为1,可以将广播定向到特定的网络部分。

例如,若要将广播发送到以192.168 打头的IP 地址标识的网络上的所有主机,请将地址的子网和主机部分全都设置为1,如192.168.255.255。

若要将广播限制在单个子网,则只将主机部分设置全都为1,如192.168.100.255。

UdpClient 类可向任何网络广播地址广播,但它无法侦听发送到网络的广播。

必须使用Socket 类才能侦听网络广播。

当所有接收者都位于单个网络中时,或者当许多客户端需要接收广播时,广播地址将起作用。

计算机毕业设计85UDP局域网QQ聊天程序设计说明书

计算机毕业设计85UDP局域网QQ聊天程序设计说明书

摘要随着网络技术的发展及人们生活的需求,网络聊天已越来越受到人们的青睐。

网络聊天已经成为人们工作生活中传递信息、交流感情的重要工具,给人们带来了很大的方便。

本设计开发的是一个局域网QQ聊天软件,运用软件工程的设计流程,使用现在比较普遍和流行的C#语言,采用面向对象的方法,综合运用数据库编程技术、多线程开发技术、网络通讯技术,以Microsoft Visual Studio 2005作为系统前台应用程序开发工具,Microsoft SQL Server 2000作为后台数据库管理系统,在Windows XP平台下进行开发。

本局域网QQ聊天软件采用服务器端/客户端(C/S)模式。

客户端采用UDP与服务器连接,客户端之间也是通过UDP互相通讯。

服务器端主要用于开启和关闭UDP协议的监听服务,还可以查看局域网内已注册的所有的用户以及他们的在线状态。

客户端分为注册窗口、登录窗口、QQ窗体主界面以及聊天界面。

服务器端要先开启监听服务,客户端才可以进行登录,然后才可以与其他登录的在线用户进行文本信息的聊天,还可以进行点对点的语音聊天,视频聊天和文件传输,还可以进行拍照和录像等。

此外,还对该软件进行了皮肤的加载以及打包成安装源。

该软件运行稳定,界面美观、操作简便。

在局域网内部使用该局域网QQ聊天软件,可以方便人与人之间的沟通、交流;可以大大提高企业的工作效率;拉近人与人之间的关系。

关键词:局域网;聊天软件;客户端;服务器端;UDP协议AbstractWith the development of networking technology and the living demand of people, chatting on network is more and more acceptable by people. Internet chat has become an important tool to transmission of information and exchange of feelings in our life, it brings a great convenience.The topic of this paper is going to talk about that to develop the local area network QQ chat software. This local area network chat software using the design stream of the software project, using the C# language which is very common and popular, using the object-oriented approach, the technology of the database programming, multi-threading development technology and the network communication technology, makes Microsoft Visual Studio 2005 as the front application design tool, Microsoft SQL Server 2000 are used as the background DBMS( the database management system ), and it was programmed in the Windows XP System.The local area network QQ chat software uses the server and client (C/S) mechanism. And the client connects the server using UDP, and they communicate each other by UDP. Server-side is mainly used to open and close the UDP protocol monitoring service, and you can also look over all the registered users and their online status whom in the local area network. Client is divided into registration window, the login window, the main QQ form and the chat form. If the client wants to log in, the server monitoring service must first open the listening service, then the client can chat with the others which have already logged, and also can voice chat, video chat and files transfers, and also can take pictures and videos. In addition, the software has been load the beautiful skin and package into the installation source.This software has an interface aesthetics, stable operation, simple operation. Using QQ software in the LAN internal can help people to communicate with others easily, can greatly improve the efficiency of the enterprises, close relationships between people.Key Words: Local Area Network; Chat Software; Client; Server-side; UDP protocol目录引言 (1)1系统概述与需求分析 (2)1.1 系统概述 (2)1.2 需求分析 (2)1.2.1功能需求 (3)1.2.2性能需求 (3)1.3 可行性分析 (4)2 系统总体设计 (5)2.1 相关开发技术的原理性说明 (5) Framework和C# (5)2.1.2SQL Server 2005 (6)2.1.3UDP协议简介 (6)2.1.4Socket简介 (6)2.2 系统功能结构 (7)2.3 业务流程图 (8)2.4 程序运行环境 (8)3 数据库以及类库的详细设计与实现 (9)3.1 数据库的创建 (9)3.1.1数据库分析 (9)3.1.2数据库创建 (9)3.1.3数据库概念设计 (9)3.1.4数据库逻辑结构设计 (9)3.1.5文件夹组织结构 (10)3.2 类库的设计 (10)4 客户端模块的详细设计及实现 (12)4.1客户端注册模块的设计 (12)4.1.1客户端注册模块概述 (12)4.1.2客户端注册模块技术分析 (13)4.1.3客户端注册模块实现过程 (13)4.2 客户端登陆模块设计 (14)4.2.1客户端登陆模块概述 (14)4.2.2客户端登陆模块技术分析 (14)4.2.3客户端登陆模块实现过程 (14)4.3 客户端QQ模块设计 (15)4.3.1客户端QQ模块概述 (15)4.3.2客户端QQ模块技术分析 (15)4.3.3客户端QQ模块实现过程 (16)4.4 客户端消息发送模块设计 (17)4.4.1客户端消息发送模块概述 (17)4.4.2客户端消息发送模块技术分析 (18)4.4.3客户端消息发送模块实现过程 (18)5 服务器端模块的详细设计与实现 (23)5.1 服务器端控制台窗体概述 (23)5.2 服务器端控制台窗体技术分析 (23)5.3 服务器端控制台窗体实现过程 (23)6 系统特色及关键技术 (24)7 结论 (25)谢辞 (28)参考文献 (29)附录 (30)引言在Internet飞速发展的今天,互联网成为人们快速获取、发布和传递信息的重要渠道,它在人们政治、经济、生活等各个方面发挥着重要的作用。

局域网聊天软件源代码包括语音聊天

局域网聊天软件源代码包括语音聊天

局域网聊天软件源代码包括语音聊天// Chat.h : PROJECT_NAME 应用程序的主头文件//#pragma once#ifndef __AFXWIN_H__#error "在包含此文件之前包含“stdafx.h”以生成PCH 文件" #endif#include "resource.h" // 主符号// CChatApp:// 有关此类的实现,请参阅Chat.cpp//class CChatApp : public CWinApp{public:CChatApp();// 重写public:virtual BOOL InitInstance();// 实现DECLARE_MESSAGE_MAP()};extern CChatApp theApp;// Chat.cpp : 定义应用程序的类行为。

//#include "stdafx.h"#include "Chat.h"#include "ChatDlg.h"//#ifdef _DEBUG//#define new DEBUG_NEW// CChatAppBEGIN_MESSAGE_MAP(CChatApp, CWinApp)ON_COMMAND(ID_HELP, &CWinApp::OnHelp)END_MESSAGE_MAP()// CChatApp 构造CChatApp::CChatApp(){// TODO: 在此处添加构造代码,// 将所有重要的初始化放置在InitInstance 中}// 唯一的一个CChatApp 对象CChatApp theApp;// CChatApp 初始化BOOL CChatApp::InitInstance(){// 如果一个运行在Windows XP 上的应用程序清单指定要// 使用ComCtl32.dll 版本6 或更高版本来启用可视化方式,//则需要InitCommonControlsEx()。

(精品)UDP局域网聊天室实现

char mtext[BUF_SZ];//消息正文
} msg_t;
分析函数实现:
服务器端:
1.int send_assign_client(int serfd,Linklist *head,msg_t *pmsg); 功能:
通过名字查找对应的客户端是否存在,存在则发送消息 不存在返回出错信息表示客户端不存在
那么我们分析一下该链表的数据结构构建。 数据结构 地址信息节点:
typedef struct node { struct sockaddr_in addr; struct node *next;
} data_t;
//消息类型
#define CLIENT_TALK 100 #define SERVER_TALK 200
分析客户端的流程:
客户端: 整体的流程首先是 网络的基本编程
socket pid = fork(); if (pid > 0) //父进程,主要功能,数据发送 {
while (1) { //大循环 1.发送一个登录的消息,告诉大家我上线了 2..从键盘获得数据 a.聊天的对端的名字 SYSTERM 群聊消息 非SYSTERM 私聊消息 c.聊天的内容 d.输入quit时,结束 3.聊天结束,发送一个聊天结束的消息给大家,告诉大家说我下线了
/* See NOTES */
} } } else if (pid == 0)//子进程,主要功能,数据接收 {
while (1) { 1.接收数据 2.显示数据
}
}
分析"服务器端"的流程:
整体的流程是 UDP的网络服务器的 基本编程
socket bind pid = fork(); if (pid >0)//父进程 发数据,系统级别的消息,给所有客户端发送消息 {

VC++之网络编程五聊天编程实例(UDP)

VC++之⽹络编程五聊天编程实例(UDP)Server:#include <Winsock2.h>#include <stdio.h>void main(){//mide delete wordWORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested=MAKEWORD(2,2);err=WSAStartup(wVersionRequested,&wsaData);if(err!=0){return;}if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wHighVersion)!=2){WSACleanup();return ;}SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM,0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);addrSrv.sin_family=AF_INET;addrSrv.sin_port=htons(6000);bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));char recvBuf[100];char sendBuf[100];char tempBuf[100];SOCKADDR_IN addrClient;int len=sizeof(SOCKADDR);while(1){recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);if('q'==recvBuf[0]){sendto(sockSrv,"q",strlen("q")+1,0,(SOCKADDR*)&addrClient,len);printf("chat end!/n");break;}sprintf(tempBuf,"%s say: %s",inet_ntoa(addrClient.sin_addr),recvBuf);printf("%s/n",tempBuf);printf("Please input data:/n");gets(sendBuf);sendto(sockSrv,sendBuf,strlen(sendBuf)+1,0,(SOCKADDR*)&addrClient,len);}closesocket(sockSrv);WSACleanup();}client:#include <Winsock2.h>#include <stdio.h>void main(){//mide delete wordWORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested=MAKEWORD(2,2);err=WSAStartup(wVersionRequested,&wsaData);if(err!=0){return;}if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wHighVersion)!=2){WSACleanup();return ;}SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");addrSrv.sin_family=AF_INET;addrSrv.sin_port=htons(6000);sendto(sockClient,"Hello",strlen("Hello")+1,0,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));closesocket(sockClient);WSACleanup();}注意:server 和 client 都要"项⽬属性"--->"配置属性"----> "链接"----> "输⼊" --->"附加依赖项"中添加"ws2_32.lib"。

局域网聊天程序作品+源代码

[原创]局域网聊天程序作品+源代码
文章标题:[原创]局域网聊天程序作品+源代码顶部 goldberg 发布于:2006-05-2415:45 [楼主][原创]局域网聊天程序作品+源代码
软件作者:Goldberg[安全矩阵]()
信息来源:邪恶八进制信息安全团队()
注意:此软件首发于安全矩阵()后由原创作者友情提交到邪恶八进制信息安全团队
用VB个做了局域网聊天的小软件,做的很垃圾,界面更是丑陋无比(自己只是个编程小菜鸟),现在发到论坛上丢人现眼一下,同时也请各位高手不吝赐教,谢谢.
六一儿童节快到了,祝天程序的作品+源代码
附件二是UDP协议下局域网聊天程序的作品+源代码
描述:TCP协议下局域网聊天程序的作品+源代码
附件:TCP实现局域网聊天.rar(15K)下载次数:302
描述:UDP协议下局域网聊天程序的作品+源代码
附件:UDP实现局域网聊天.rar(31K)下载次数:175(c)Copyleft2003-2007,EvilOctalSecurityTeam.
ThisfileisdecompiledbyanunregisteredversionofChmDecompiler.
Regsiteredversiondoesnotshowthismessage.
YoucandownloadChmDecompilerat:/

C基于UDP实现一个简易的聊天室

C基于UDP实现⼀个简易的聊天室引⾔ 本⽂是围绕Linux udp api 构建⼀个简易的多⼈聊天室.重点看思路,帮助我们加深对udp开发中⼀些api了解.相对⽽⾔udp socket开发相⽐tcp socket开发注意的细节要少很多.但是⽔也很深. 本⽂就当是⼀个demo整合帮助开发者回顾和继续了解 linux udp开发的基本流程.⾸先我们来看看 linux udp 和 tcp的异同./*这⾥简单⽐较⼀下TCP和UDP在编程实现上的⼀些区别:TCP流程建⽴⼀个TCP连接需要三次握⼿,⽽断开⼀个TCP则需要四个分节。

当某个应⽤进程调⽤close(主动端)后(可以是服务器端,也可以是客户端),这⼀端的TCP发送⼀个FIN,表⽰数据发送完毕;另⼀端(被动端)发送⼀个确认,当被动端待处理的应⽤进程都处理完毕后,发送⼀个FIN到主动端,并关闭套接⼝,主动端接收到这个FIN后再发送⼀个确认,到此为⽌这个TCP连接被断开。

UDP套接⼝ UDP套接⼝是⽆连接的、不可靠的数据报协议;既然他不可靠为什么还要⽤呢? 其⼀:当应⽤程序使⽤⼴播或多播是只能使⽤UDP协议; 其⼆:由于它是⽆连接的,所以速度快。

因为UDP套接⼝是⽆连接的,如果⼀⽅的数据报丢失,那另⼀⽅将⽆限等待,解决办法是设置⼀个超时。

在编写UDP套接⼝程序时,有⼏点要注意:建⽴套接⼝时socket函数的第⼆个参数应该是SOCK_DGRAM,说明是建⽴⼀个UDP套接⼝;由于UDP是⽆连接的,所以服务器端并不需要listen或accept函数;当UDP套接⼝调⽤connect函数时,内核只记录连接放的IP地址和端⼝,并⽴即返回给调⽤进程.*/参照/wocjj/article/details/8315559/Jessy/p/3536163.html这⾥简单引述⼀下 udp相⽐tcp ⽤到的两个api . recvfrom()/sendto() 具体细节如下#include <sys/types.h>#include <sys/socket.h>/** 这两个函数基本等同于⼀个 send 和 recv . 详细参数解释如下* s : ⽂件描述符,等同于 socket返回的值* buf : 数据其实地址* len : 发送数据长度或接受数据缓冲区最⼤长度* flags : 发送标识,默认就⽤O.带外数据使⽤ MSG_OOB, 偷窥⽤MSG_PEEK .....* addr : 发送的⽹络地址或接收的⽹络地址* alen : sento标识地址长度做输⼊参数, recvfrom表⽰输⼊和输出参数.可以为NULL此时addr也要为NULL* : 返回0表⽰执⾏成功,否则返回<0 . 更多细节查询man⼿册*/extern int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *addr, int alen);extern int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *addr, int *alen);上⾯就是两个函数的⼤致⽤法. 具体可以查看linux api帮助⼿册. 最好就⽤ man sendto / man recvfrom 把那⼀系列函数都看看.现在很多⽂章都是转载,但是找不见转载的地址, 下⾯会举⼀个简易的UDP回显服务器的demo加深理解.前⾔⾸先看设计图有点low. 简单看看吧. 那我们先看客户端代码 udpclt.c 代码#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define _SHORT_PORT (8088)//// udp client heoo//int main(int argc, char * argv[]) {int fd, len;struct sockaddr_in ar = { AF_INET };socklen_t al = sizeof (struct sockaddr_in);char msg[BUFSIZ] = ":) 谁也不会喜欢⼯作狂 ~";// 创建 client socketif ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {perror("main socket dgram");exit(EXIT_FAILURE);}ar.sin_port = htons(_SHORT_PORT);// 开始发送消息包到服务器, 默认⾛ INADDR_ANYsendto(fd, msg, sizeof msg - 1, 0, (struct sockaddr *)&ar, al);// 开始接收服务器回过来的报⽂len = recvfrom(fd, msg, sizeof msg - 1, 0, (struct sockaddr *)&ar, &al);if (len == -1) {perror("main recvfrom");exit(EXIT_FAILURE);}msg[len] = '\0';printf("[%s:%hd] -> %s\n", inet_ntoa(ar.sin_addr), ntohs(ar.sin_port), msg); // 程序结束return close(fd);}编译是gcc -g -Wall -o udpclt.out udpclt.cudp 服务器 udpsrv.c#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/socket.h>#define _SHORT_PORT (8088)//// udp server heoo//int main(int argc, char * argv[]) {int fd, len;struct sockaddr_in ar = { AF_INET };socklen_t al = sizeof (struct sockaddr_in);char msg[BUFSIZ];if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {perror("main socket dgram");exit(EXIT_FAILURE);}printf("udp server start [%d][0.0.0.0][%hd] ...\n", fd, _SHORT_PORT);// 服务器绑定地址ar.sin_port = htons(_SHORT_PORT);if (bind(fd, (struct sockaddr *)&ar, al) == -1) {perror("main bind INADDR_ANY");exit(EXIT_FAILURE);}// 阻塞的接收不同客户端数据来回搞while ((len = recvfrom(fd, msg, sizeof msg - 1, 0, (struct sockaddr *)&ar, &al)) > 0) {msg[len] = '\0';printf("[%s:%hd] -> %s\n", inet_ntoa(ar.sin_addr), ntohs(ar.sin_port), msg);// 回显继续发送给客户端sendto(fd, msg, len, 0, (struct sockaddr *)&ar, al);}return close(fd);}编译是gcc -g -Wall -o udpsrv.out udpsrv.c后⾯运⾏结果如下 udp服务器如下 (Ctrl + C 退出)udp 客户端如下(修改了⼀版本, 当前版本更加简单, 容易理解.)到这⾥将上⾯代码敲⼀遍基本上 udp ⼀套 api 就会使⽤了. 后⾯进⼊正题设计聊天室代码.正⽂ ⾸先看客户端设计代码. 主要思路是⼦进程处理数据的输出, ⽗进程处理服务器数据的接收. 具体设计如下(画的图有点low就不画了.../(ㄒo ㄒ)/~~)udpmulclt.c#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <signal.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/socket.h>// 名字长度包含'\0'#define _INT_NAME (64)// 报⽂最⼤长度,包含'\0'#define _INT_TEXT (512)//4.0 控制台打印错误信息, fmt必须是双引号括起来的宏#define CERR(fmt, ...) \fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\__FILE__, __func__, __LINE__, errno, strerror(errno),##__VA_ARGS__)//4.1 控制台打印错误信息并退出, t同样fmt必须是 ""括起来的字符串常量#define CERR_EXIT(fmt,...) \CERR(fmt,##__VA_ARGS__),exit(EXIT_FAILURE)/** 简单的Linux上API错误判断检测宏, 好⽤值得使⽤*/#define IF_CHECK(code) \if((code) < 0) \CERR_EXIT(#code)// 发送和接收的信息体struct umsg{char type; //协议 '1' => 向服务器发送名字, '2' => 向服务器发送信息, '3' => 向服务器发送退出信息char name[_INT_NAME]; //保存⽤户名字char text[_INT_TEXT]; //得到⽂本信息,空间换时间};/** udp聊天室的客户端, ⼦进程发送信息,⽗进程接受信息*/int main(int argc, char* argv[]) {int sd, rt;struct sockaddr_in addr = { AF_INET };socklen_t alen = sizeof addr;pid_t pid;struct umsg msg = { '1' };// 这⾥简单检测if(argc != 4) {fprintf(stderr, "uage : %s [ip] [port] [name]\n", argv[0]);exit(-1);}// 下⾯对接数据if((rt = atoi(argv[2]))<1024 || rt > 65535)CERR("atoi port = %s is error!", argv[2]);// 接着判断ip数据IF_CHECK(inet_aton(argv[1], &addr.sin_addr));addr.sin_port = htons(rt);// 这⾥拼接⽤户名字strncpy(, argv[3], _INT_NAME - 1);//创建socket 连接IF_CHECK(sd = socket(PF_INET, SOCK_DGRAM, 0));// 这⾥就是发送登录信息给udp聊天服务器了IF_CHECK(sendto(sd, &msg, sizeof msg, 0, (struct sockaddr*)&addr, alen));//开启⼀个进程, ⼦进程处理发送信息, ⽗进程接收信息IF_CHECK(pid = fork());if(pid == 0) { //⼦进程,先忽略退出处理防⽌成为僵⼫进程signal(SIGCHLD, SIG_IGN);while(fgets(msg.text, _INT_TEXT, stdin)){if(strcasecmp(msg.text, "quit\n") == 0){ //表⽰退出msg.type = '3';// 发送数据并检测IF_CHECK(sendto(sd, &msg, sizeof msg, 0, (struct sockaddr*)&addr, alen));break;}// 洗唛按发送普通信息msg.type = '2';IF_CHECK(sendto(sd, &msg, sizeof msg, 0, (struct sockaddr*)&addr, alen));}// 处理结算操作,并杀死⽗进程close(sd);kill(getppid(), SIGKILL);exit(0);}// 这⾥是⽗进程处理数据的读取for(;;){bzero(&msg, sizeof msg);IF_CHECK(recvfrom(sd, &msg, sizeof msg, 0, (struct sockaddr*)&addr, &alen));[_INT_NAME-1] = msg.text[_INT_TEXT-1] = '\0';switch(msg.type){case'1':printf("%s 登录了聊天室!\n", );break;case'2':printf("%s 说了: %s\n", , msg.text);break;case'3':printf("%s 退出了聊天室!\n", );break;default://未识别的异常报⽂,程序直接退出fprintf(stderr, "msg is error! [%s:%d] => [%c:%s:%s]\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port), msg.type, , msg.text);goto __exit;}}__exit:// 杀死并等待⼦进程退出close(sd);kill(pid, SIGKILL);waitpid(pid, NULL, -1);return0;}这⾥主要需要注意的是// 发送和接收的信息体struct umsg{char type; //协议 '1' => 向服务器发送名字, '2' => 向服务器发送信息, '3' => 向服务器发送退出信息char name[_INT_NAME]; //保存⽤户名字char text[_INT_TEXT]; //得到⽂本信息,空间换时间};传输和接收的数据格式, type表⽰协议或⾏为. 我这⾥细⼼了处理 name, text最后⼀个字符必须是 '\0'. 其它都是业务代码.再扯⼀点struct sockaddr_in addr = { AF_INET };等价于struct sockaddr_in addr;memset(&addr, 0, sizeof addr);addr.sin_family = AF_INET;也是⼀个C开发中技巧吧. 再扯⼀点linux上提供 bzero函数, 但是window上没有. 写了个通⽤的如下//7.0 置空操作#ifndef BZERO//v必须是个变量#define BZERO(v) \memset(&v,0,sizeof(v))#endif/* !BZERO */可以试试吧毕竟跨平台....好了那我们说 udp 聊天室的服务器设计思路. 就是服务器会维护⼀个客户端链表. 有信息来就⼴播. 好简单吧.就是这样.正常的事都简单.简单的是美的. 好了看代码总设计和实现. udpmulsrv.c#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <signal.h>#include <sys/wait.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/socket.h>// 名字长度包含'\0'#define _INT_NAME (64)// 报⽂最⼤长度,包含'\0'#define _INT_TEXT (512)//4.0 控制台打印错误信息, fmt必须是双引号括起来的宏#define CERR(fmt, ...) \fprintf(stderr,"[%s:%s:%d][error %d:%s]" fmt "\r\n",\__FILE__, __func__, __LINE__, errno, strerror(errno),##__VA_ARGS__)//4.1 控制台打印错误信息并退出, t同样fmt必须是 ""括起来的字符串常量#define CERR_EXIT(fmt,...) \CERR(fmt,##__VA_ARGS__),exit(EXIT_FAILURE)/** 简单的Linux上API错误判断检测宏, 好⽤值得使⽤*/#define IF_CHECK(code) \if((code) < 0) \CERR_EXIT(#code)// 发送和接收的信息体struct umsg{char type; //协议 '1' => 向服务器发送名字, '2' => 向服务器发送信息, '3' => 向服务器发送退出信息char name[_INT_NAME]; //保存⽤户名字char text[_INT_TEXT]; //得到⽂本信息,空间换时间};// 维护⼀个客户端链表信息,记录登录信息typedef struct ucnode {struct sockaddr_in addr;struct ucnode* next;} *ucnode_t ;// 新建⼀个结点对象static inline ucnode_t _new_ucnode(struct sockaddr_in* pa){ucnode_t node = calloc(sizeof(struct ucnode), 1);if(NULL == node)CERR_EXIT("calloc sizeof struct ucnode is error. ");node->addr = *pa;return node;}// 插⼊数据,这⾥head默认头结点是当前服务器结点static inline void _insert_ucnode(ucnode_t head, struct sockaddr_in* pa) {ucnode_t node = _new_ucnode(pa);node->next = head->next;head->next = node;}// 这⾥是有⽤户登录处理static void _login_ucnode(ucnode_t head, int sd, struct sockaddr_in* pa, struct umsg* msg) {_insert_ucnode(head, pa);head = head->next;// 从此之后才为以前的链表while(head->next){head = head->next;IF_CHECK(sendto(sd, msg, sizeof(*msg), 0, (struct sockaddr*)&head->addr, sizeof(struct sockaddr_in)));}}// 信息⼴播static void _broadcast_ucnode(ucnode_t head, int sd, struct sockaddr_in* pa, struct umsg* msg) {int flag = 0; //1表⽰已经找到了while(head->next) {head = head->next;if((flag) || !(flag=memcmp(pa, &head->addr, sizeof(struct sockaddr_in))==0)){IF_CHECK(sendto(sd, msg, sizeof(*msg), 0, (struct sockaddr*)&head->addr, sizeof(struct sockaddr_in)));}}}// 有⼈退出群聊static void _quit_ucnode(ucnode_t head, int sd, struct sockaddr_in* pa, struct umsg* msg) {int flag = 0;//1表⽰已经找到while(head->next) {if((flag) || !(flag = memcmp(pa, &head->next->addr, sizeof(struct sockaddr_in))==0)){IF_CHECK(sendto(sd, msg, sizeof(*msg), 0, (struct sockaddr*)&head->next->addr, sizeof(struct sockaddr_in))); head = head->next;}else { //删除这个退出的⽤户ucnode_t tmp = head->next;head->next = tmp->next;free(tmp);}}}// 销毁维护的对象池,没有往复杂的考虑了简单处理退出了static void _destroy_ucnode(ucnode_t* phead) {ucnode_t head;if((!phead) || !(head=*phead)) return;while(head){ucnode_t tmp = head->next;free(head);head = tmp;}*phead = NULL;}/** udp聊天室的服务器, ⼦进程⼴播信息,⽗进程接受信息*/int main(int argc, char* argv[]) {int sd, rt;struct sockaddr_in addr = { AF_INET };socklen_t alen = sizeof addr;struct umsg msg;ucnode_t head;// 这⾥简单检测if(argc != 3) {fprintf(stderr, "uage : %s [ip] [port]\n", argv[0]);exit(-1);}// 下⾯对接数据if((rt = atoi(argv[2]))<1024 || rt > 65535)CERR("atoi port = %s is error!", argv[2]);// 接着判断ip数据IF_CHECK(inet_aton(argv[1], &addr.sin_addr));addr.sin_port = htons(rt); //端⼝要采⽤⽹络字节序// 创建socketIF_CHECK(sd = socket(PF_INET, SOCK_DGRAM, 0));// 这⾥bind绑定设置的地址IF_CHECK(bind(sd, (struct sockaddr*)&addr, alen));//开始监听了head = _new_ucnode(&addr);for(;;){bzero(&msg, sizeof msg);IF_CHECK(recvfrom(sd, &msg, sizeof msg, 0, (struct sockaddr*)&addr, &alen));[_INT_NAME-1] = msg.text[_INT_TEXT-1] = '\0';fprintf(stdout, "msg is [%s:%d] => [%c:%s:%s]\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port), msg.type, , msg.text);// 开始判断处理switch(msg.type) {case'1':_login_ucnode(head, sd, &addr, &msg);break;case'2':_broadcast_ucnode(head, sd, &addr, &msg);break;case'3':_quit_ucnode(head, sd, &addr, &msg);break;default://未识别的异常报⽂,程序把其踢⾛fprintf(stderr, "msg is error! [%s:%d] => [%c:%s:%s]\n", inet_ntoa(addr.sin_addr),ntohs(addr.sin_port), msg.type, , msg.text);_quit_ucnode(head, sd, &addr, &msg);break;}}// 这段代码是不会执⾏到这的, 可以加⼀些控制让其⾛到这. 看⼈close(sd);_destroy_ucnode(&head);return0;}这⾥主要围绕的结构就是// 维护⼀个客户端链表信息,记录登录信息typedef struct ucnode {struct sockaddr_in addr;struct ucnode* next;} *ucnode_t ;注册添加登录⼴播退出等.这⾥再扯⼀下. 关于C static开发技巧. C中有⼀种 *.h 开发模式, 全部采⽤static 内嵌代码段. 这样可以省略*.c ⽂件. ⼩巧的封装可以使⽤. 继续扯⼀点. 开发也写C++,虽然鄙视. C++ 中有个 *.hpp⽂件. ⽐较好. 它表达的意思是这个代码是开源的. 全部采⽤充⾎模型. 类中代码都放在类中实现.⾮常值得提倡. 这也是学boost的时候学到的. 很实在.好了说代码吧. 也⽐较随⼤流. 看看也都明⽩了. 简单分析⼀处吧// 这⾥是有⽤户登录处理static void _login_ucnode(ucnode_t head, int sd, struct sockaddr_in* pa, struct umsg* msg) {_insert_ucnode(head, pa);head = head->next;// 从此之后才为以前的链表while(head->next){head = head->next;IF_CHECK(sendto(sd, msg, sizeof(*msg), 0, (struct sockaddr*)&head->addr, sizeof(struct sockaddr_in)));}}因为我采⽤的头查法. 那就除了刚插⼊的头的下⼀个结点都需要发送登录信息. ⽐较精巧.好看编译命令gcc -g -Wall -o udpmulsrv.out udpmulsrv.cgcc -g -Wall -o udpmulclt.out udpmulclt.c最后测试截图如下很好玩,欢迎尝试.到这⾥基本上udp基础api 应该都了解了.从上⾯代码也许能看出来. 设计⽐较重要. 设计决定⼤思路.下次有机会要么分享开源的⽹络库,要么分享数据库开发.后记 错误是难免的,欢迎吐槽交流. ( ^_^ )/~~拜拜别董⼤(其⼀) ⾼适千⾥黄云⽩⽇曛,北风吹雁雪纷纷。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <signal.h>#define CLIENT_LOGIN 100#define CLIENT_CHAT 200#define CLIENT_QUIT 300#define SERVER_CHA T 400#define SERVER_QUIT 500struct node{char name[20];struct sockaddr_in client_addr;struct node *next;};struct message{long type;char name[20];char mtext[512];};struct node *create_list(void);void insert_list(struct node *, char *, struct sockaddr_in *);void delete_list(struct node *, char *);void recv_message(int , struct node *);void send_message(int , struct sockaddr_in *, pid_t );void client_login(int , struct node *, struct message *, struct sockaddr_in *); void client_chat(int , struct node *, struct message *);void client_quit(int , struct node *, struct message *);void server_chat(int , struct node *, struct message *);void server_quit(int , struct node *, struct message *);void brocast_msg(int , struct node *, struct message *);void father_func(int sig_no){return ;}int main(int argc, const char *argv[]){int socket_fd;pid_t pid;struct sockaddr_in server_addr;struct node *head;if (argc < 3){fprintf(stderr, "usages : %s ip port\n", argv[0]);exit(-1);}if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){perror("failed to create socket");exit(-1);}head = create_list();server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr = inet_addr(argv[1]);if (bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {perror("failed to bind");exit(-1);}if ((pid = fork()) < 0) //创建子经常{perror("failed to fork pid");exit(-1);}if (pid == 0)recv_message(socket_fd, head);elsesend_message(socket_fd, &server_addr, pid);return 0;}struct node *create_list(void){struct node *head;head = (struct node *)malloc(sizeof(struct node));head->next = NULL;return head;}void insert_list(struct node *head, char *name, struct sockaddr_in *client_addr) {struct node *new;new = (struct node *)malloc(sizeof(struct node));strcpy(new->name, name);new->client_addr = *client_addr;new->next = head->next;head->next = new;return ;}void delete_list(struct node *head, char *name){struct node *p = head->next;struct node *q = head;while (p != NULL){if (strcmp(p->name, name) == 0)break;p = p->next;q = q->next;}q->next = p->next;p->next = NULL;free(p);return ;}void recv_message(int socket_fd, struct node *head){struct message msg;struct sockaddr_in client_addr;int client_addrlen = sizeof(struct sockaddr);while (1){if (recvfrom(socket_fd, &msg, sizeof(msg), 0, (struct sockaddr *)&client_addr, &client_addrlen) < 0){perror("failed to recvform client");exit(-1);}switch(msg.type){case CLIENT_LOGIN:client_login(socket_fd, head, &msg, &client_addr);break;case CLIENT_CHA T:client_chat(socket_fd, head, &msg);break;case CLIENT_QUIT:client_quit(socket_fd, head, &msg);break;case SERVER_CHA T:server_chat(socket_fd, head, &msg);break;case SERVER_QUIT:server_quit(socket_fd, head, &msg);break;default:break;}}return ;}void send_message(int socket_fd, struct sockaddr_in *server_addr, pid_t pid){struct message msg;char buf[512];signal(getppid(), father_func);while (1){usleep(500);printf(">");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;strcpy(msg.mtext, buf);strcpy( , "server");msg.type = SERVER_CHA T;if (strncmp(buf, "quit", 4) == 0){msg.type = SERVER_QUIT;if (sendto(socket_fd, &msg, sizeof(msg), 0,(struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) {perror("failed to send server_quit message");exit(-1);}pause();kill(pid, SIGKILL);waitpid(pid, NULL, 0);exit(0);}if (sendto(socket_fd, &msg, sizeof(msg), 0, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0){perror("failed to send server_chat message");exit(-1);}}return ;}void client_login(int socket_fd, struct node *head, struct message *msg, struct sockaddr_in *client_addr){printf("********Login In********\n");printf("%s is Login In\n", msg->name);printf("************************\n");insert_list(head, msg->name, client_addr);brocast_msg(socket_fd, head, msg);return ;}void client_chat(int socket_fd, struct node *head, struct message *msg){printf("********Group Chat********\n");printf("name: %s\n", msg->name);printf("msg: %s\n", msg->mtext);printf("**************************\n");brocast_msg(socket_fd, head, msg);return ;}void client_quit(int socket_fd, struct node *head, struct message *msg){printf("*********Quit Msg********\n");printf("%s is Quit\n", msg->name);printf("*************************\n");delete_list(head, msg->name);brocast_msg(socket_fd, head, msg);return ;}void server_chat(int socket_fd, struct node *head, struct message *msg){printf("********Server Msg*********\n");printf("msg: %s\n", msg->mtext);printf("***************************\n");brocast_msg(socket_fd, head, msg);return ;}void server_quit(int socket_fd, struct node *head, struct message *msg){brocast_msg(socket_fd, head, msg);kill(getppid(), SIGUSR1);return ;}void brocast_msg(int socket_fd, struct node *head, struct message *msg){struct node *p = head->next;while(p != NULL){if (msg->type == CLIENT_LOGIN){if (strcmp(p->name, msg->name) == 0){p = p->next;continue;}}sendto(socket_fd, msg, sizeof(struct message), 0, (struct sockaddr *)&(p->client_addr), sizeof(struct sockaddr));p = p->next;}return ; }#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <signal.h>#define CLIENT_LOGIN 100#define CLIENT_CHAT 200#define CLIENT_QUIT 300#define SERVER_CHA T 400#define SERVER_QUIT 500struct message{long type;char name[20];char mtext[512];};void recv_message(int );void send_message(int , struct sockaddr_in *, char *, pid_t);void login_msg(struct message *);void group_msg(struct message *);void quit_msg(struct message *);void server_msg(struct message *);void server_quit(void);int main(int argc, char *argv[]){pid_t pid;int server_fd;struct sockaddr_in server_addr;if (argc < 4){fprintf(stderr, "usages: %s ip port name\n", argv[0]);exit(-1);}if ((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){perror("failed to create server_fd");exit(-1);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr = inet_addr(argv[1]);if ((pid = fork()) < 0){perror("failed to fork pid");exit(-1);}if (pid == 0)recv_message(server_fd);elsesend_message(server_fd, &server_addr, argv[3], pid);return 0;}void recv_message(int server_fd){struct message msg;while (1){memset(&msg, 0, sizeof(msg));if (recvfrom(server_fd, &msg, sizeof(msg), 0, NULL, NULL) < 0){perror("failed to recv server message");exit(-1);}switch(msg.type){case CLIENT_LOGIN:login_msg(&msg);break;case CLIENT_CHA T:group_msg(&msg);break;case CLIENT_QUIT:quit_msg(&msg);break;case SERVER_CHA T:server_msg(&msg);break;case SERVER_QUIT:server_quit();break;default:break;}}return ;}void send_message(int server_fd, struct sockaddr_in *server_addr, char *name, pid_t pid) {struct message msg;char buf[512];msg.type = CLIENT_LOGIN;strcpy(, name);if (sendto(server_fd, &msg, sizeof(msg), 0,(struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) {perror("failed to send login message");exit(-1);}while(1){memset(buf, 0, sizeof(buf));memset(&msg, 0, sizeof(msg));usleep(500);printf(">");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;strcpy(msg.mtext, buf);strcpy(, name);msg.type = CLIENT_CHAT;if (strncmp(buf, "quit", 4) == 0){msg.type = CLIENT_QUIT;if (sendto(server_fd, &msg, sizeof(msg), 0,(struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) {perror("failed to send quit message");exit(-1);}kill(pid, SIGKILL);waitpid(pid, NULL, 0);exit(0);}if (sendto(server_fd, &msg, sizeof(msg), 0,(struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) {perror("failed to send group message");exit(-1);}}return ;}void login_msg(struct message *msg)printf("######## Login in ########\n");printf("%s is login in\n", msg->name);printf("######## Login in ########\n");return ;}void group_msg(struct message *msg){printf("******** Group Msg ********\n");printf("name: %s\n", msg->name);printf("msg: %s\n", msg->mtext);printf("******** Group Msg ********\n");return ;}void quit_msg(struct message *msg){printf("######## Quit Msg ########\n");printf("%s is Quit\n", msg->name);printf("######## Quit Msg ########\n");return ;}void server_msg(struct message *msg){printf("******** Server Msg ********\n");printf("msg: %s\n", msg->mtext);printf("******** Server Msg ********\n");return ;}void server_quit(void ){kill(getppid(), SIGKILL);exit(0);}。

相关文档
最新文档