Linux下的Socket网络编程:一个简易聊天室的实现-徐慧军
socket编程聊天室基本流程
socket编程聊天室基本流程一、引言Socket编程是一种用于网络通信的编程技术。
它允许程序员创建客户端和服务器应用程序,这些应用程序可以在不同的计算机上运行并通过Internet或局域网相互通信。
在本文中,我们将介绍Socket编程聊天室的基本流程。
二、Socket编程概述Socket编程是一种基于TCP/IP协议的网络编程技术。
它使用套接字(socket)来实现网络通信。
套接字是一种抽象概念,它表示一个网络连接点,可以用来发送和接收数据。
在Socket编程中,客户端和服务器之间建立一个连接,然后通过这个连接进行数据传输。
客户端向服务器发送请求,并等待服务器响应。
服务器接收请求并处理它,并将响应发送回客户端。
三、Socket编程聊天室基本流程1. 创建服务器程序首先,我们需要创建一个服务器程序来监听客户端连接请求。
在Python中,可以使用socket模块来创建套接字对象,并使用bind()方法将其绑定到指定的IP地址和端口号上。
2. 创建客户端程序然后,我们需要创建一个客户端程序来连接到服务器。
同样地,在Python中可以使用socket模块来创建套接字对象,并使用connect()方法连接到指定的IP地址和端口号上。
3. 实现消息传输一旦客户端和服务器之间建立了连接,它们就可以开始进行消息传输。
在Socket编程中,可以使用send()方法将数据发送到对方,使用recv()方法从对方接收数据。
4. 实现聊天室功能为了实现聊天室功能,我们需要让多个客户端能够同时连接到服务器,并且能够相互通信。
为此,我们可以使用多线程或异步编程技术来实现。
在多线程模式下,每个客户端连接都会被分配一个独立的线程来处理。
这个线程负责接收客户端发送的消息,并将其转发给其他客户端。
在异步编程模式下,我们可以使用协程或回调函数来处理消息传输。
当有新的消息到达时,就会触发相应的回调函数进行处理。
5. 实现用户管理为了实现用户管理功能,我们需要让每个客户端都能够注册一个唯一的用户名,并且能够查看当前在线的用户列表。
C#基于Socket实现简单聊天室功能
C#基于Socket实现简单聊天室功能因为这段时间在学习Socket,所以就试着写了⼀个简单的聊天室。
主要分为服务器端和多个客户端。
利⽤服务器端作数据中转站,实现消息群发。
1、服务器端有两个类:using System.Collections.Generic;using ;using .Sockets;namespace 聊天室_Socket_TCP_服务器端{class Program{static List<Client> clients = new List<Client>();static List<Client> notClients = new List<Client>();/// <summary>/// ⼴播消息/// </summary>/// <param name="message"></param>public static void CastMessageTOAllConnetedClients(string message){foreach (var client in clients){if (client.Conneted){client.CastMessage(message);}else{notClients.Add(client);}}foreach (var temp in notClients){clients.Remove(temp);}}static void Main(string[] args){Socket tcpSever = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);tcpSever.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 8899));tcpSever.Listen(100);//监听是否有客户端发起连接Console.WriteLine("Begin to listen...");while (true){Socket clientSocket = tcpSever.Accept();if (clientSocket!=null){Console.WriteLine("A client has connneted...");Client client = new Client(clientSocket);//将每个新创建的连接通信放于client类做通信clients.Add(client);}}Console.ReadKey();}}}using System;using .Sockets;using System.Text;using System.Threading;namespace 聊天室_Socket_TCP_服务器端{/// <summary>/// 利⽤该类和客户端做通信/// </summary>class Client{public Socket clientSocket;private Thread mesManageTherad;private byte[] bufffer=new byte[20];public Client(Socket soc){clientSocket = soc;//由于消息是不断发送的,需要多次进⾏处理。
基于Socket接口的Linux与Windows网络聊天室设计与实现
基于Socket接口的Linux与Windows网络聊天室设计与实现作者:陈洁孟晓景来源:《软件导刊》2015年第06期摘要:为了实现Linux与Windows跨平台通信,及时共享信息,构建了一个适用于跨平台的网络聊天室通信程序。
先搭建跨平台通信环境,然后使用Socket套接字网络编程接口实现通信。
整个系统采用客户机/服务器(C/S)模型,Windows客户端采用MFC框架编写,Linux 服务器和客户端均采用C语言实现。
通过测试,Linux和Windows的客户端可以成功连接到服务器,从而实现跨平台网络聊天功能。
关键词:Linux;Windows;套接字;客户机/服务器DOIDOI:10.11907/rjdk.151230中图分类号:TP319文献标识码:A 文章编号:16727800(2015)006009403作者简介作者简介:陈洁(1990-),女,山东菏泽人,山东科技大学信息科学与工程学院硕士研究生,研究方向为计算机网络应用技术;孟晓景(1962-),男,浙江绍兴人,山东科技大学信息科学与工程学院教授,研究方向为计算机网络。
0 引言Linux是一个基于POSIX和UNIX的多任务、多用户、支持多线程的操作系统。
Linux在众多方面表现出强大的优势,通常用在控制领域以提高系统性能。
然而,目前使用最多的Windows操作系统图形界面友好,拥有良好的集成开发环境,操作简单,深受广大用户的喜爱。
两种操作系统各有千秋,越来越多场合同时使用,这就出现了跨平台的通信问题。
对此,本文通过Socket套接口来实现不同操作系统之间的实时聊天,运用C/S模式设计出Windows 与Linux操作系统间可以互相通信的网络聊天室,本客户端可以显示其它客户端的消息,实现了信息的及时共享。
1 Socket编程原理与过程1.1 Socket编程原理Socket[1]作为BSD UNIX的进程通信机制,通常也称作“套接字”,用于描述IP地址和端口,是网络通信的基本单元。
Linux下的网络编程与Socket通信
Linux下的网络编程与Socket通信在Linux操作系统中,网络编程是一项重要而复杂的技术,而Socket通信则是其中的核心内容。
本文将深入探讨Linux下的网络编程与Socket通信相关的知识和技巧。
一、Linux网络编程概述Linux网络编程指的是在Linux环境下开发网络应用程序的技术。
在Linux系统中,网络编程主要基于Socket套接字实现,通过Socket 套接字,应用程序可以与网络上的其他设备进行通信。
二、Socket通信基础知识1. 什么是Socket?Socket是一种抽象的概念,它提供了一种通信机制,使得不同设备之间可以进行数据传输和通信。
在Linux中,Socket通信是通过套接字(Socket)来实现的。
2. Socket通信的类型Socket通信有两个基本的类型:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。
- 流式Socket是一种面向连接的Socket,使用TCP协议,数据传输是可靠和有序的,适用于需要建立可靠连接的数据传输。
- 数据报式Socket是一种无连接的Socket,使用UDP协议,数据传输是不可靠和无序的,适用于对实时性要求较高的数据传输。
三、Linux下的网络编程步骤在Linux下进行网络编程时,我们需要按照以下步骤进行:1. 创建Socket:选择合适的Socket类型,创建一个Socket套接字。
2. 绑定Socket:将Socket与本地地址绑定,以便其他设备可以通过该地址找到它。
3. 监听连接请求(仅适用于流式Socket):对于服务端,需要监听来自客户端的连接请求。
4. 接受连接请求(仅适用于流式Socket):对于服务端,接受客户端的连接请求,建立连接。
5. 连接Socket:对于客户端,连接到服务端的Socket。
6. 发送和接收数据:通过Socket进行数据的发送和接收。
7. 关闭Socket:通信结束后,关闭Socket套接字。
Linux下Socket网络编程
Linux下S ocket网络编程,文件传输,数据传输的C语言例子2010年03月11日星期四 16:15什么是Sock etSocket接口是TCP/IP网络的AP I,Socket接口定义了许多函数或例程,程序员可以用它们来开发TC P/IP网络上的应用程序。
要学Inter net上的T CP/IP网络编程,必须理解Soc ket接口。
Socket接口设计者最先是将接口放在Unix操作系统里面的。
如果了解Uni x系统的输入和输出的话,就很容易了解S ocket了。
网络的 Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。
Socket也具有一个类似于打开文件的函数调用So cket(),该函数返回一个整型的S ocket描述符,随后的连接建立、数据传输等操作都是通过该S ocket实现的。
常用的Sock et类型有两种:流式Socke t (SOCK_ST REAM)和数据报式So cket(SOCK_DG RAM)。
流式是一种面向连接的Soc ket,针对于面向连接的TCP服务应用;数据报式Socke t是一种无连接的Sock et,对应于无连接的UDP服务应用。
Socket建立为了建立Soc ket,程序可以调用S ocket函数,该函数返回一个类似于文件描述符的句柄。
socket函数原型为:int socket(int domain, int type, int protoco l);domain指明所使用的协议族,通常为PF_I NET,表示互联网协议族(TCP/IP协议族);type参数指定socke t的类型: SOCK_ST REAM 或SOCK_D GRAM,Socket接口还定义了原始Socke t(SOCK_RA W),允许程序使用低层协议;protoco l通常赋值"0"。
linux下socket编程
UNIX 系统的 I/O 命令集,是从 Maltics 和早期系统中的命令演变出来的,其模式为打 开一读/写一关闭 (open-write-read-close)。在 一个用户进程进行 I/O 操作时,它首 先调用“打开”获得对指定文件或设备的使用权,并返回称为文件描述符的整型数,以描述 用户在打开的文件或设备上进行 I /O 操作的进程。然后这个用户进程多次调用“读/写”以 传输数据。当所有的传输操作完成后,用户进程关闭调用,通知操作系统已经完成了对某对 象的使用。
2.2.3 客户/服务器模式
在 TCP/IP 网络应用中,通信的两个进程间相互作用的主要模式是客户/服务器模式(Cl ient/Server model),即客户向服务器发出服务请求,服务器接收到请求后,提供相应的 服务。客户/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资 源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少 的客户请求服务这一非对等作用。其次,网间进程通信完全是异步 的,相互通信的进程间 既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联 系,为二者的数据交换提供同步,这就是基于客户/ 服务器模式的 TCP/IP。
其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。因此, 网间进程通信还要解决多重协议的识别问题。
为了解决上述问题,TCP/IP 协议引入了下列几个概念。
端口
网络中可以被命名和寻址的通信端口,是操作系统可分配的一种资源。
按照 OSI 七层协议的描述,传输层与网络层在功能上的最大区别是传输层提供进程通信 能力。从这个意义上讲,网络通信的最终地址就不仅仅是主机地址 了,还包括可以描述进 程的某种标识符。为此,TCP/IP 协议提出了协议端口(protocol port,简称端口)的概 念,用于标识通信的进程。
python实现简易聊天室(Linux终端)
python实现简易聊天室(Linux终端)本⽂实例为⼤家分享了python实现简易聊天室的具体代码,供⼤家参考,具体内容如下群聊聊天室1.功能:类似qq群聊功能1.有⼈进⼊聊天室需要输⼊姓名,姓名不能重复2.有⼈进⼊聊天室,其他⼈会受到通知xxx进⼊聊天室3.⼀个⼈发消息,其他⼈会受到消息xxx:xxxxxxxx4.有⼈退出聊天室,其他⼈也会收到通知xxx退出聊天室5.扩展功能:服务端消息公告,服务端发送消息所有⼈都能收到管理员消息:xxxxxxxx2.确定技术模型1.服务端和客户端服务端处理请求,发送管理员消息客户端执⾏各种功能2.套接字选择:udp套接字3.消息发送模型:转发客户端 ~> 服务端 ~> 其他客户端4.存储⽤户信息:{name:addr}5.处理收发关系:多进程分别处理收发3.注意事项1.设计封装⽅案2.写⼀个功能模块测试⼀个模块3.注意注释的添加#coding =utf-8'''chat roomenv:python3.5exc:socket and forkname:mianmabbemail:****************服务端功能:1.搭建⽹络通信2.处理进⼊聊天室* 接收姓名* 判断是否允许进⼊* 将结果反馈给客户端* 如果不允许则结束,允许则将⽤户插⼊数据结构* 给其他⼈发送通知3.处理聊天* 接收消息,判断消息类型,分为L(输⼊姓名),C(发消息),Q(退出聊天室)* 将消息转发4.处理退出聊天室5.发送管理员消息'''from socket import *from os import *from sys import *user = {} #创建空字典⽤来存储⽤户的昵称和地址#处理登录def do_login(s,name,addr):if name in user: #判断昵称是否已经存在s.sendto('该昵称已被占⽤'.encode(),addr)returnelse: #昵称不存在,则发送约定好的'OK's.sendto(b'OK',addr)#功能:有⼈进⼊聊天室,其他⼈会收到消息msg = '\n 欢迎 %s 进⼊聊天室 '%namefor i in user: #发送该条消息给其他⽤户s.sendto(msg.encode(),user[i])user[name] = addr #将该⽤户插⼊数据结构(字典)#处理聊天def do_chat(s,name,text):msg = '%s : %s'%(name,text) #设置消息显⽰格式for i in user:s.sendto(msg.encode(),user[i])#处理退出def do_quit(s,name):msg = '%s 退出了聊天室'%namefor i in user:if i != name: #给其他⼈发送该⽤户退出的消息s.sendto(msg.encode(),user[i])else: #给该⽤户客户端发送约定好的EXIT让⽗进程退出s.sendto(b'EXIT',user[i])del user[name] #删除字典中该⽤户#处理请求def do_request(s):#循环接受所有客户请求while True:try:data,addr = s.recvfrom(1024)except KeyboardInterrupt: #捕获⽗进程直接退出错误exit('服务端退出!')# print(data.decode())msgList = data.decode().split() #按空格拆分为列表,⽅便索引 if msgList[0] == 'L': #判断消息类型do_login(s,msgList[1],addr)elif msgList[0] == 'C':text = ' '.join(msgList[2:]) #将消息中可能有的空格加回来 do_chat(s,msgList[1],text)elif msgList[0] == 'Q':do_quit(s,msgList[1])def main():s = socket(AF_INET,SOCK_DGRAM)ADDR = ('0.0.0.0',8888)s.bind(ADDR)#创建进程pid = fork()if pid < 0:print('Error')elif pid == 0: #⼦进程⽤来发送管理员消息while True:try:text = input('管理员 : ')except KeyboardInterrupt: #捕获⼦进程直接退出错误exit()msg ='C 管理员 %s'%texts.sendto(msg.encode(),ADDR)else: #⽗进程⽤来处理请求do_request(s)main()客户端功能:'''1.搭建通信2.进⼊聊天室* 输⼊姓名* 发送给服务器* 接收服务器反馈* 不允许则重新输⼊,允许则进⼊聊天室* 创建新的进程⽤于消息收发3.聊天* 循环发送消息消息类型分为L(输⼊姓名),C(发消息),Q(退出聊天室)* 循环接收消息4.退出聊天室5.接受管理员消息'''from socket import *from os import *from sys import *ADDR = ('127.0.0.1',8888) #填写服务端地址#循环发送消息def send_msg(s,name):while True:try:text = input() #客户输⼊要发送的消息except KeyboardInterrupt: #⼦进程防⽌⽤户Ctrl+C直接退出text = 'quit'if text.strip() == 'quit': #规定输⼊quit退出msg = 'Q ' + name #消息类型,姓名s.sendto(msg.encode(),ADDR)exit('您已退出聊天室')else:msg = 'C %s %s'%(name,text) #消息类型,姓名,消息s.sendto(msg.encode(),ADDR)#循环接收信息def recv_msg(s):while True:try:data,addr = s.recvfrom(1024)except KeyboardInterrupt: #⽗进程防⽌⽤户Ctrl+C直接退出exit()if data.decode() =='EXIT': #当⽤户退出,⽆需再收消息,约定EXIT让⽗进程退出 exit() #退出⽗进程print(data.decode())#创建⽹络连接def main():s = socket(AF_INET,SOCK_DGRAM)while True:name = input('请输⼊昵称:') #输⼊姓名if not name:returnmsg = 'L ' +name#发送请求s.sendto(msg.encode(),ADDR)#等待回复data,addr = s.recvfrom(1024)if data.decode() == 'OK':print('您已进⼊聊天室')breakelse: #登录失败print(data.decode()) #直接打印服务端的错误信息#创建进程pid = fork()if pid < 0:print('Error')elif pid == 0: #⼦进程发消息send_msg(s,name)else: #⽗进程收消息recv_msg(s)main()先运⾏服务端,再运⾏客户端以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
基于Linux的socket网络编程聊天工具课程设计
*****《软件综合开发案例教程》课程设计报告课程设计题目小组成员:**,**,**,**任课讲师和助教:**,**2014年 10 月 29 日摘要这个课程设计整体采用在linux平台下,在同一局域网内实现聊天功能。
整体框架主要分为服务端和客户端两个部分,设置好ip和端口号,在Linux下编译和调试两主大块程序,实现服务端和客户端的连接,然后以服务端作为中继转实现客户端之间的通信。
使用socket网络编程采用TCP/IP协议保证连接可靠,并在项目管理中采用linux流行的gcc和makefile编译,提高了编译和调试效率,加快了项目的完成速度。
本次设计的聊天工具采用字符串命令行的方式进行通信,主要实现了五个功能:用户之间一对一的聊天、编辑、换行、用户之间聊天记录保存、聊天记录调取。
经过测试,程序运行可靠,能满足在linux中实现网络聊天的要求。
关键词 linux,socket,gedit,服务端,客户端,网络编程AbstractThe course design of the overall use in the Linux platform, within the same LAN chat functions.Overall framework consists of server and client two parts, set up IP and port number, two main large program under Linux compiling and debugging, to connect server and client, and then turn to the server as a relay to realize the communication between the e the socket network programming using TCP/IP protocol to ensure reliable connect, and using Linux popular GCC in project management and compile a makefile, improve the efficiency of the compiling and debugging, to speed up the completion of the project.The design way of chat tool USES the string on the command line to communicate, has realized the five main functions: the one-on-one chat between users, editing, line feeds, chat records, chat records obtained between users.After testing, the program runs, reliable and can meet the requirements of the implementation in the Linux network chat. Keywords Linux, socket, gedit, server, client, network programming目录摘要 (II)Abstract (II)第一章绪论.......................................................................................... - 1 -1.1、背景......................................................................................... - 1 -1.2、网络聊天的发展状况 ............................................................ - 1 -1.3、Linux系统............................................................................ - 2 -1.3.1 、Linux的简介............................................................... - 2 -1.3.2 、Linux发展历程........................................................... - 3 - 第二章系统应用技术 ......................................................................... - 4 -2.1 、socket概念及功能 ............................................................... - 4 -2.2、socket类型 ........................................................................... - 5 -2.3 、socket函数 ........................................................................... - 5 -2.3.1 、API功能介绍.............................................................. - 5 -2.3.2、套接口地址结构 ........................................................... - 7 -2.3.3、基本转换函数 ............................................................... - 8 -2.3.4、socket编程流程 ............................................................ - 8 -2.4、TCP/IP 协议......................................................................... - 10 -2.4.1、协议概述 ..................................................................... - 10 -2.4.2、TCP/IP层次结构 ........................................................ - 10 - 第三章需求分析 ............................................................................... - 13 -3.1 、功能需求 ............................................................................ - 13 -3.2、性能需求 .............................................................................. - 13 -3.3 、模块划分 ............................................................................ - 13 -3.3.1、界面需求设计 ........................................................... - 14 -3.3.2 、通信需求 ................................................................... - 14 -3.3.3 、数据存储 ................................................................... - 14 -3.4、系统总流程图 ...................................................................... - 14 - 第四章系统测试 ............................................................................... - 15 -4.1、测试说明 .............................................................................. - 15 -4.2、模块测试 .............................................................................. - 15 -4.3、测试结果分析 ...................................................................... - 16 - 第五章设计和实现 ........................................................................... - 16 -5.1、窗体的设计 .......................................................................... - 16 -5.2、实现服务器与客户端的连接 .............................................. - 17 -5.3、聊天功能 .............................................................................. - 18 -5.4、编辑功能的实现 .................................................................. - 19 -5.5、换行功能的实现 .................................................................. - 20 -5.6、数据库的创建与连接 .......................................................... - 21 -5.6.1、MySQL数据库的简介 ............................................... - 21 -5.6.2、MYSQL环境搭建 ...................................................... - 21 -5.7 、显示聊天记录 .................................................................... - 23 -结论................................................................................................ - 25 - 致谢................................................................................................ - 26 -第一章绪论1.1、背景随着Internet的快速发展和普及,网络已经遍布世界各个角落。
Linux C的socket聊天室设计与实现
基于Linux C的socket聊天室1 系统功能1.1 支持群聊天。
1. 2 支持向指定用户发送悄悄话功能。
1. 3 支持不同消息不同颜色显示。
1. 4 用户名为登录的唯一标示,所以不允许重名,客户端登录具有重名检查功能。
1. 5 支持上线下线通知。
1. 6 支持服务器发送系统消息功能。
1. 7 支持登录时检测服务器是否在线。
1. 8 支持服务器下线通知客户端,客户端强行下线。
2 硬件平台2.1 功能用来作为对Linux C程序所用软件以及操作系统的安装的载体,2. 2 特点计算机的整体配置还算不错,4G内存,500G硬盘,1G独立显卡等,使得运行一般的大游戏都不卡。
2. 3 组成K43T系列华硕计算机一台,外加键盘一个。
3 软件平台3.1 操作系统平台主要有Windows7操作系统和ubuntu操作系统,电脑以安装Window7为主,ubuntu操作系统以虚拟系统的方式安装在电脑上。
3. 2 系统软件平台主要用到的软件有:Linux的ubuntu操作系统,VMware Workstation软件,Window7下的记事本软件,wps软件和CodeBlocks C编程软件以及GCC编译器等等。
3. 3 系统设计3.3.1模块设计主要写了两个模块程序,一个是服务端程序,另一个是客户端程序,在服务端程序主要完成对服务的基本配置以及对客户端程序的一些初始化参数进行设计等,实现端用户聊天的功能。
在客户端程序里,完成对客户信息的封装,可以供多个客户同时登陆,并能对错误信息给出对应的提示,方便用户使用。
服务程序文件盒客户端程序文件分别为server.c和client.c,使用Gcc来调试运行成server和client文件,先启动server程序,配置服务端信息,然后启动客户端client程序,用户登陆,进行聊天。
3.3.2 服务端程序server.c主要代码如下:typedef struct {char name[10];SA_IN address;} USER;//XXX :用户链表typedef struct Hnode_list {USER data;struct Hnode_list *next;} Hlink, *plink;int memoryError(plink p);int creatUserList(plink head);int findUser(plink head, char name[10]);int delUser(plink head, char name[10]);int getAllUser(plink const head);int addUser(plink head, USER data);//XXX :用户链表void ProcessLogin(char* command, SA_IN rec_addr);void ProcessChat(char* command);void ProcessQuit(char* command);int ProcessPrivate(char* command,SA_IN rec_addr);void ProcessAd();void sig_int(int signum);//ctl+c关掉服务器static plink head;static int socket_fd;int main(void) {char buf[BUFFERSIZE];SA_IN address, rec_addr;socklen_t length;struct timeval tv;_sec=60;//插播广告时间_usec=0;head = malloc(sizeof(Hlink));//用户列表头creatUserList(head); //创建列表signal(SIGINT,sig_int);if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {perror("Socket creation fails");exit(-1);}memset(&address, 0, sizeof(address));address.sin_family = AF_INET;address.sin_addr.s_addr = inet_addr(SERVER_IP);address.sin_port = htons(SERVER_PORT);if (bind(socket_fd, (SA *) &address, sizeof(address)) == -1) { perror("Socket is bound to fail");exit(-1);}//30秒没有收到任何消息就发送广告printf("The server to start successip:%s\n",inet_ntoa(address.sin_addr));length = sizeof(rec_addr);setsockopt(socket_fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));while (1) {memset(buf,0,sizeof(buf));//服务器只有此处用来接收if (recvfrom(socket_fd, buf, sizeof(buf), 0, (SA *) &rec_addr, &length) == -1){buf[0]='A';//发送广告标志位}switch (buf[0]) {case 'L'://登录ProcessLogin(buf, rec_addr);break;case 'C'://群聊天ProcessChat(buf);break;case 'Q'://退出ProcessQuit(buf);break;case 'A'://广告ProcessAd();break;case 'P'://悄悄话ProcessPrivate(buf,rec_addr);break;default:printf("ERROR");break;}}}3.3.3 客户端client.c主要代码如下:#define BUFFERSIZE 1024typedef struct sockaddr SA;typedef struct sockaddr_in SA_IN;#define SERVER_IP "127.0.0.1"#define SERVER_PORT 8000void sig_user1(int signo);void sig_user2(int signo);void sig_alrm(int signo);char* ProcessLogin(SA_IN serv_addr);//以下为无关紧要的功能函数声明void dispDot();int msSleep(long ms);static pid_t pid;static int socket_fd;int main(void) {char buf[BUFFERSIZE];char buf_temp[BUFFERSIZE];char name[10];SA_IN serv_addr;signal(SIGUSR1, sig_user1);signal(SIGUSR2,sig_user2);signal(SIGINT,SIG_IGN);//拒绝用户ctrl+c强制退出,只能键入quit退出if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {perror("socket build error");exit(-1);}//XXX:服务器配置信息memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);serv_addr.sin_port = htons(SERVER_PORT);//XXXstrcpy(name, ProcessLogin(serv_addr));//得到登录名if ((pid = fork()) == -1) {perror("child process build error");return -1;}if (pid == 0)///////////////////////////////////子进程,用来接收服务器的消息{memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);sprintf(buf, "C%s On-line", name);if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &serv_addr, sizeof(serv_addr)) < 0){perror("On-line failure");}kill(getppid(), SIGUSR1);//唤醒主进程让其输入while (1) {memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);if (recvfrom(socket_fd, buf, sizeof(buf), 0, NULL, NULL) < 0) { perror("Receive messages failure");}if (strncmp("Q",buf,1) == 0) //接收服务器下线通知{printf("\033[22;30m%s", buf+1); //输出黑色文字系统消息kill(getppid(), SIGUSR2);kill(getpid(), SIGUSR2);}else if (strncmp("A",buf,1) == 0){printf("\033[22;96m%s", buf+1); //输出灰色文字系统消息}else if (strncmp("P",buf,1) == 0){printf("\033[22;31m%s", buf+1); //输出红色文字系统消息}else if (strncmp("R",buf,1) == 0){if (strncmp(buf+1, name, strlen(name)) == 0){sprintf(buf_temp, "me%s", buf + strlen(name)+1);printf("\033[22;32m%s", buf_temp);//输出黄色文字自己的消息}elseprintf("\033[22;33m[Messages are received @]%s", buf+1); //输出绿色文字}printf("\033[22;30m");//恢复黑色}}//////////////////////////////////////////////////////主进程////////////////////////////////////pause(); //等待SIGUSR1int quit_flag = 0;getchar();//清空输入名字时残存的回车符,因为ProcessLogin使用scanf while (1)//父进程{memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);fgets(buf_temp,BUFFERSIZE,stdin); //采用fgets比采用scanf好,聊天时可以键入空格buf_temp[strlen(buf_temp)-1]='\0';if (strncmp("quit", buf_temp, 4) == 0) //退出{sprintf(buf, "Q%s", name);quit_flag = 1;}//键入$开头为悄悄话else if (strncmp("$", buf_temp, 1) == 0) //注:发送悄悄话的格式:$对方名称$消息内容{char *check=buf_temp+1; //必须对其检查一定要有两个$...$否则造成服务器当机while(*check!='\0'&&*check!='$') check++;if(*check!='$'){printf("[system] \n message format: $ each other name $ message content \n < enter >\n");continue;}sprintf(buf, "P%s%s", name,buf_temp);}else //群发消息{sprintf(buf, "C%s say:%s", name, buf_temp);}//开始发送消息if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &serv_addr, sizeof(serv_addr)) < 0){perror("Send failure");}if (quit_flag){kill(pid, SIGUSR2);break;}}kill(getpid(), SIGUSR2);}4 系统测试测试数据及截图如下所示:5 系统源码5.1 服务端源码#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <dirent.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <netdb.h>#include <signal.h>#define BUFFERSIZE 1024typedef struct sockaddr SA;typedef struct sockaddr_in SA_IN;#define SERVER_IP "127.0.0.1"#define SERVER_PORT 8000#include <time.h>typedef struct {char name[10];SA_IN address;} USER;//XXX :用户链表typedef struct Hnode_list {USER data;struct Hnode_list *next;} Hlink, *plink;int memoryError(plink p);int creatUserList(plink head);int findUser(plink head, char name[10]); int delUser(plink head, char name[10]); int getAllUser(plink const head);int addUser(plink head, USER data);//XXX :用户链表void ProcessLogin(char* command, SA_IN rec_addr);void ProcessChat(char* command);void ProcessQuit(char* command);int ProcessPrivate(char* command,SA_IN rec_addr);void ProcessAd();void sig_int(int signum);//ctl+c关掉服务器static plink head;static int socket_fd;int main(void) {char buf[BUFFERSIZE];SA_IN address, rec_addr;socklen_t length;struct timeval tv;_sec=60;//插播广告时间_usec=0;head = malloc(sizeof(Hlink));//用户列表头creatUserList(head); //创建列表signal(SIGINT,sig_int);if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {perror("Socket creation fails");exit(-1);}memset(&address, 0, sizeof(address));address.sin_family = AF_INET;address.sin_addr.s_addr = inet_addr(SERVER_IP);address.sin_port = htons(SERVER_PORT);if (bind(socket_fd, (SA *) &address, sizeof(address)) == -1) { perror("Socket is bound to fail");exit(-1);}//30秒没有收到任何消息就发送广告printf("The server to start successip:%s\n",inet_ntoa(address.sin_addr));length = sizeof(rec_addr);setsockopt(socket_fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));while (1) {memset(buf,0,sizeof(buf));//服务器只有此处用来接收if (recvfrom(socket_fd, buf, sizeof(buf), 0, (SA *) &rec_addr, &length) == -1){buf[0]='A';//发送广告标志位}switch (buf[0]) {case 'L'://登录ProcessLogin(buf, rec_addr);break;case 'C'://群聊天ProcessChat(buf);break;case 'Q'://退出ProcessQuit(buf);break;case 'A'://广告ProcessAd();break;case 'P'://悄悄话ProcessPrivate(buf,rec_addr);break;default:printf("ERROR");break;}}}void ProcessLogin(char* command, SA_IN rec_addr) {char name[10];USER user;char buf[BUFFERSIZE];memset(buf,'\0',BUFFERSIZE);strcpy(name, command + 1);if (findUser(head, name) == -1) {strcpy(, name);user.address = rec_addr;addUser(head, user);buf[0] = 'Y';if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &rec_addr,sizeof(rec_addr)) == -1){perror("Login failed");}}else {buf[0] = 'N';if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &rec_addr,sizeof(rec_addr)) == -1){perror("Login failed");}}}void ProcessChat(char* command) {char buf[BUFFERSIZE];SA_IN address;memset(buf,'\0',BUFFERSIZE);sprintf(buf, "R%s\n<Please enter the>\n", command + 1); //'\n'强行推送数据必须否则要到缓冲区满才一次性发送plink p = head->next;while (p != NULL) {address = (p->data).address;if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &address,sizeof(address)) < 0){perror("Message sent failure");}p = p->next;}}void ProcessQuit(char* command) {char name[10];char buf[BUFFERSIZE];memset(buf,'\0',BUFFERSIZE);SA_IN address;sprintf(name, "%s", command + 1);plink p = head->next;delUser(head, name);sprintf(buf, "R%s Get offline\n", name);while (p != NULL) {address = (p->data).address;if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &address,sizeof(address)) < 0){perror("Message sent failure");}p = p->next;}}void ProcessAd(){char buf[BUFFERSIZE];char buf_temp[BUFFERSIZE];memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);SA_IN address;plink p = head->next;strcat(buf,"A<<System message>>The current online users\n");while (p != NULL){sprintf(buf_temp,"[%s:%s] ", (p->data).name, inet_ntoa((p->data).address.sin_addr));strcat(buf,buf_temp);p = p->next;}strcat(buf,"\n<Please enter the>\n");p = head->next;while (p != NULL) {address = (p->data).address;if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &address,sizeof(address)) < 0){perror("Message sent failure");}p = p->next;}}int ProcessPrivate(char* command,SA_IN rec_addr){char buf[BUFFERSIZE];char buf_temp[BUFFERSIZE];char name_from[10];char name_to[10];int non_user_flag=0;int i,j;for(i=1,j=0;command[i]!='$';i++,j++){name_from[j]=command[i];}name_from[j]='\0';i++;for(j=0;command[i]!='$';i++,j++){name_to[j]=command[i];}name_to[j]='\0';i++;memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);strcpy(buf_temp,command+i);strcat(buf_temp,"\n<Please enter the>\n");//双方名字及消息准备就绪sprintf(buf,"P[from%sThe whispers]%s",name_from,buf_temp);plink p = head->next;SA_IN address;while (p != NULL) {if (strcmp((p->data).name, name_to) == 0){address = (p->data).address;break;}p = p->next;}if (p == NULL)non_user_flag=1;if(!non_user_flag){if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &address,sizeof(address)) < 0){perror("Whispers send failure");}sprintf(buf,"R%s Have received the message, the wisps sent successfully\n<Please enter the>\n",name_to);if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *)&rec_addr,sizeof(address)) < 0){perror("Message sent failure");}}else{sprintf(buf,"R%s not on-line,Whispers send failure\n<Please enter the>\n",name_to);if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &rec_addr,sizeof(address)) < 0){perror("Whispers send failure");}}return 0;}void sig_int(int signum){char buf[BUFFERSIZE];plink p = head->next;SA_IN address;sprintf(buf,"Q The server is offline\n");while (p != NULL) {address = (p->data).address;if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &address,sizeof(address)) < 0){perror("Offline messages sent to the client");}p = p->next;}printf("Server is shut down\n");exit(0);}//XXX:使用带头结点的单向链表存放用户信息int memoryError(plink p) //判断内存是否申请成功{if (p == NULL) {printf("MEMORY ERROR!");return 1;}return 0;}int creatUserList(plink head) {if (memoryError(head))return -1;head->next = NULL;}int addUser(plink head, USER data) //始终在表头插入{plink new_create = malloc(sizeof(Hlink));if (memoryError(new_create))return -1;new_create->data = data;new_create->next = head->next;head->next = new_create;}int delUser(plink head, char name[10]) {plink q = head;plink p = head->next;while (p != NULL) {if (strcmp((p->data).name, name) == 0)break;q = p;p = p->next;}if (p == NULL) {printf("Delete user failure\n");return -1;}q->next = p->next;free(p);p = NULL;}int findUser(plink head, char name[10]) { plink p = head->next;while (p != NULL) {if (strcmp((p->data).name, name) == 0)return 0;p = p->next;}if (p == NULL)return -1;}5.2 客户端源码#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <dirent.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <netdb.h>#include <signal.h>#define BUFFERSIZE 1024typedef struct sockaddr SA;typedef struct sockaddr_in SA_IN;#define SERVER_IP "127.0.0.1"#define SERVER_PORT 8000void sig_user1(int signo);void sig_user2(int signo);void sig_alrm(int signo);char* ProcessLogin(SA_IN serv_addr); //以下为无关紧要的功能函数声明void dispDot();int msSleep(long ms);static pid_t pid;static int socket_fd;int main(void) {char buf[BUFFERSIZE];char buf_temp[BUFFERSIZE];char name[10];SA_IN serv_addr;signal(SIGUSR1, sig_user1);signal(SIGUSR2,sig_user2);signal(SIGINT,SIG_IGN);//拒绝用户ctrl+c强制退出,只能键入quit退出if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {perror("socket build error");exit(-1);}//XXX:服务器配置信息memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP);serv_addr.sin_port = htons(SERVER_PORT);//XXXstrcpy(name, ProcessLogin(serv_addr));//得到登录名if ((pid = fork()) == -1) {perror("child process build error");return -1;}if (pid == 0)///////////////////////////////////子进程,用来接收服务器的消息{memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);sprintf(buf, "C%s On-line", name);if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &serv_addr, sizeof(serv_addr)) < 0){perror("On-line failure");}kill(getppid(), SIGUSR1);//唤醒主进程让其输入while (1) {memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);if (recvfrom(socket_fd, buf, sizeof(buf), 0, NULL, NULL) < 0) { perror("Receive messages failure");}if (strncmp("Q",buf,1) == 0) //接收服务器下线通知{printf("\033[22;30m%s", buf+1); //输出黑色文字系统消息kill(getppid(), SIGUSR2);kill(getpid(), SIGUSR2);}else if (strncmp("A",buf,1) == 0){printf("\033[22;96m%s", buf+1); //输出灰色文字系统消息}else if (strncmp("P",buf,1) == 0){printf("\033[22;31m%s", buf+1); //输出红色文字系统消息}else if (strncmp("R",buf,1) == 0){if (strncmp(buf+1, name, strlen(name)) == 0){sprintf(buf_temp, "me%s", buf + strlen(name)+1);printf("\033[22;32m%s", buf_temp);//输出黄色文字自己的消息}elseprintf("\033[22;33m[Messages are received @]%s", buf+1); //输出绿色文字}printf("\033[22;30m");//恢复黑色}}//////////////////////////////////////////////////////主进程////////////////////////////////////pause(); //等待SIGUSR1int quit_flag = 0;getchar();//清空输入名字时残存的回车符,因为ProcessLogin使用scanf while (1)//父进程{memset(buf,'\0',BUFFERSIZE);//必须清空否则会有虚假数据memset(buf_temp,'\0',BUFFERSIZE);fgets(buf_temp,BUFFERSIZE,stdin); //采用fgets比采用scanf好,聊天时可以键入空格buf_temp[strlen(buf_temp)-1]='\0';if (strncmp("quit", buf_temp, 4) == 0) //退出{sprintf(buf, "Q%s", name);quit_flag = 1;}//键入$开头为悄悄话else if (strncmp("$", buf_temp, 1) == 0) //注:发送悄悄话的格式:$对方名称$消息内容{char *check=buf_temp+1; //必须对其检查一定要有两个$...$否则造成服务器当机while(*check!='\0'&&*check!='$') check++;if(*check!='$'){printf("[system] \n message format: $ each other name $ message content \n < enter >\n");continue;}sprintf(buf, "P%s%s", name,buf_temp);}else //群发消息{sprintf(buf, "C%s say:%s", name, buf_temp);}//开始发送消息if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &serv_addr, sizeof(serv_addr)) < 0){perror("Send failure");}if (quit_flag){kill(pid, SIGUSR2);break;}}kill(getpid(), SIGUSR2);}//////////////////////////////////////////////Siganl///////////////////// /////////////////////////void sig_user2(int signo) {printf("%dEnd of the process\n", getpid());exit(-1);}void sig_user1(int signo) {;}void sig_alrm(int signo){return ;}//////////////////////////////////////////////Siganl///////////////////// /////////////////////////char* ProcessLogin(SA_IN serv_addr) {char buf[10];static char name[10];struct sigaction act; //处理服务器未上线sigaction(SIGALRM,NULL,&act);act.sa_handler=sig_alrm;act.sa_flags&=~SA_RESTART; //有何用处??????sigaction(SIGALRM,&act,NULL);while (1) {printf("Please enter your user name:");buf[0] = 'L';scanf("%s", buf + 1);strcpy(name, buf + 1);alarm(2);//设置连接服务器超时时间为2秒printf("In the login");dispDot();if (sendto(socket_fd, buf, sizeof(buf), 0, (SA *) &serv_addr, sizeof(serv_addr)) < 0){perror("Login failed");}recvfrom(socket_fd, buf, sizeof(buf), 0, NULL, NULL);if (buf[0] == 'N') {printf("This user name has been used, please enter the username again\n");} else if (buf[0] == 'Y') {printf("%slogin success\n",name);alarm(0);//必须关闭闹钟return name;break;}else{printf("The server is not online, log out\n");exit(-1);}}}////////////////////一些无关紧要的功能函数void dispDot(){int i;for(i=0;i<10;i++){printf(". ");fflush(stdout);msSleep(90000);}printf("\n");}int msSleep(long ms){struct timeval tv;_sec = 0;_usec = ms;return select(0, NULL, NULL, NULL, &tv);}。
简单实现linux聊天室程序
简单实现linux聊天室程序花了很长时间⽤来练习掌握linux上socket的⼀个聊天室程序,可以实现的哦。
具体代码如下代码⼀:#ifndef _I_H#define _I_H#include <math.h>#include <stdio.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <inttypes.h>#include <time.h>#include <sys/ioctl.h>#include <net/if.h>#include <signal.h>#include <ncurses.h>#include <math.h>#define SEVR_IP "127.0.0.1"#define SEVR_PORT 8081#define CNTNT_LEN 150#define MSG_LEN sizeof(struct msg)#define ADDR_LEN sizeof(struct sockaddr)#define USR_LEN sizeof(struct user)#define PRT_LEN 8#define HSTR_LEN sizeof(struct chat_history)/* declare Global variables */int mainfd;/* used as chat histroy file handle*/int sockfd;/* used as socket local handle */int count;struct sockaddr_in server;/* msg is used for communicating message */struct msg{int flag; /* flag meaning:1,ordinary; 2,log msg; 3,reg msg, other,file*/int id_from;int id_to;char content[CNTNT_LEN];char append[10];};/* user is used information list */struct user{int id;char name[10];char password[10];char *p_chatlog;struct sockaddr user_addr;};/* chat_history used for reading chat history */struct chat_history{char content[CNTNT_LEN];char time[25];/* i_functions below is funtions needed by both client and sever */ extern int i_saveto_chat(struct msg *pmsg);int i_clean_stdin (){while ('\n' == getchar()){continue;}return(0);}int i_print(char *pmsg, int size){int i = 1;for (i; i<= size; i++){if (*pmsg != '\n'){printf("%c", *pmsg);pmsg ++;}else{return(0);}}return(0);}int i_input(char *p_input){char c = '\0';int i;for (i = 0; i < CNTNT_LEN; i++){p_input[i] = getchar();if (p_input[i] =='\n'){return(0);}}printf("you have input long enough!\n");return(0);}int i_socket(int domain, int type, int protocol){int fd;if ((fd = socket(domain, type, protocol)) == -1){perror("creat socket error:");exit(1);}return(fd);}int i_bind(int fd, const struct sockaddr *addr, int namelen){if (-1 == bind(fd, addr, namelen)){perror("i_bind error:");exit(1);}return (0);if (-1 == recvfrom(fd, buf, len, flags, addr, size)){perror("i_recvfrom error:");exit(1);}return(0);}int i_sendto(int fd, void *buf, size_t len, int flags,struct sockaddr *addr, int size){if (-1 == sendto(fd, buf, len, flags, addr, size)){perror("i_sendto error");exit(1);}return (0);}int i_open(const char *pathname, int flags){int fd;if ((fd = open(pathname, flags)) == -1){perror("open_failed");exit(1);}return (fd);}int i_read(int fd, void *msg, int len){if(-1 == read(fd, msg, len)){perror("i_read error");exit(1);}return(0);}int i_write(int fd, void *msg, int len){if (-1 == write(fd, msg, len)){perror("i_write error");exit(0);}return(0);}/* init a socket,file and server addr */int i_init(){mainfd = i_open("./chat_log", O_RDWR|O_CREAT); sockfd = i_socket(AF_INET, SOCK_DGRAM, 0); /* initialize server address */bzero(&server, sizeof(server));server.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &server.sin_addr); server.sin_port = htons(SEVR_PORT);perror("init");return (0);}char *i_get_time(){time_t time_now;int i_lseek(int fd, off_t size, int position){if (-1 == lseek(fd, size, position)){perror("seek error");exit(1);}return(0);}int i_saveto_chat(struct msg *pmsg){struct chat_history hstr;bzero(&hstr, HSTR_LEN);count = count + 1;hstr.count =count;hstr.from = pmsg->id_from;hstr.to = pmsg->id_to;strncpy(hstr.content, pmsg->content, CNTNT_LEN); strncpy(hstr.time, i_get_time(), 25);i_lseek(mainfd, 0, SEEK_END);i_write(mainfd, &hstr, HSTR_LEN);return(0);}int i_print_history(int len, int i){struct chat_history chat_reader;int j;int position;bzero(&chat_reader, HSTR_LEN);if (i != 0){position = len*i*HSTR_LEN;i_lseek(mainfd, position, SEEK_END);}else{position = len*i*HSTR_LEN;i_lseek(mainfd, HSTR_LEN, SEEK_SET);}for (j = 1; j <= len; j++){i_read(mainfd, &chat_reader, HSTR_LEN);printf("\n#item%d:id%dto id%d \n", j,chat_reader.from, chat_reader.to);i_print(chat_reader.content, CNTNT_LEN);printf("\n Time:%s\n", chat_reader.time);}return(0);}#endif代码⼆:#include "i.h"int user_list_fd;/* start:initialization */int init(){struct user usr;/* init the user list file's fist user to 0*/memset((struct user*)&usr, '\0', sizeof(struct user));i_lseek(user_list_fd, 0, SEEK_SET);i_write(user_list_fd, (char*)&usr, USR_LEN);/* bind the struct sockaddr_in server to the sockfd */i_bind(sockfd, (struct sockaddr*)&server, ADDR_LEN);struct chat_history apple;bzero(&apple, HSTR_LEN);i_lseek(mainfd, 0, SEEK_SET);i_write(mainfd, &apple, HSTR_LEN);i_lseek(mainfd, -HSTR_LEN, SEEK_END);i_read(mainfd, &apple, HSTR_LEN);count = apple.count;return(0);}/* end:initialization *//* start:message control */int send_msg(struct msg *msg_recv, struct sockaddr *addr){int i;struct user usr;/* a common message come */printf("a ordinar message come !\n");i = msg_recv->id_to;i_lseek(user_list_fd, i*USR_LEN, SEEK_SET);i_read(user_list_fd, &usr, USR_LEN);strncpy(msg_recv->append, , 10);i_sendto(sockfd, msg_recv, MSG_LEN, 0,&(er_addr), ADDR_LEN);printf("id%d send a message to id%d sucess!\n", msg_recv->id_from, msg_recv->id_to); return(0);}int check_login(struct msg *msg_recv, struct sockaddr *addr){int i = msg_recv->id_from;;struct user usr;/* a login requet */printf("a login request come!\n");/* get the id's information */i_lseek(user_list_fd, i*USR_LEN, SEEK_SET);i_read(user_list_fd, &usr, USR_LEN);int n;n = strcmp(usr.password, msg_recv->content);/* 如果验证成功,则发送成功信息 */if (n == 0){/* save user new address */i_lseek(user_list_fd, -USR_LEN, SEEK_CUR);er_addr = *addr;i_write(user_list_fd, &usr, USR_LEN);/* tell user pass */i_sendto(sockfd, (struct msg*)msg_recv, sizeof(struct msg), 0,&(er_addr), ADDR_LEN);}else{/* 出错的话的respond */msg_recv->flag = -1;i_sendto(sockfd, (struct msg*)msg_recv, sizeof(struct msg), 0,&(er_addr), ADDR_LEN);}return(1);}printf("Id %d login sucess!\n", i);return(0);}int reg_user(struct msg *msg_recv, struct sockaddr *addr){struct user usr;printf("a regit requet come:\n");/* find the last user and hava the please to add a new user */int n;i_lseek(user_list_fd, -USR_LEN, SEEK_END);i_read(user_list_fd, &usr, USR_LEN);/* 把新⽤户的信息赋值到usr然后填⼊到user list file中 */const char *name;const char *password;name = &(msg_recv->content[0]);password = &(msg_recv->content[10]);strcpy((), name);strcpy(usr.password, password);memcpy(&(er_addr),addr, ADDR_LEN);usr.id = (usr.id + 1);i_lseek(user_list_fd, 0, SEEK_END);i_write(user_list_fd, &usr, USR_LEN);msg_recv->id_from = usr.id;/* regist to the user list then tell the user reg success */i_sendto(sockfd, (struct msg*)msg_recv, sizeof(struct msg), 0,addr, ADDR_LEN);printf("Id %d regist sucess!\n", usr.id);return(0);}int msg_cntl(){struct msg msg_recv;struct sockaddr addr_recv;printf("begin listen input...\n");int size = ADDR_LEN;for (;;){bzero(&msg_recv, MSG_LEN);i_recvfrom(sockfd, &msg_recv, sizeof(struct msg), 0,&addr_recv, &size);printf("message received...\n");i_saveto_chat(&msg_recv);switch (msg_recv.flag){case 1 :send_msg(&msg_recv,(struct sockaddr*)&addr_recv);/* send ordinary chat */ break;case 2 :check_login(&msg_recv, (struct sockaddr*)&addr_recv);break;case 3 :reg_user(&msg_recv, (struct sockaddr*)&addr_recv);}return(0);}/* end:message control*//* start:exit_sys()*/int exit_sys(){close(sockfd);close(mainfd);close(user_list_fd);printf("exit system");kill(0, SIGABRT);exit(0);}/* end:exit_sys()*//* start:chat_history*/int get_page_size(){struct chat_history page_size_reader;i_lseek(mainfd, -HSTR_LEN, SEEK_END);i_read(mainfd, &page_size_reader, HSTR_LEN);return(page_size_reader.count);}int read_chat_history(){printf("****char*history***");printf("(n-nextpage; p-prepage; q-quit)\n");int page_num;/* */int remains;int berry = get_page_size();page_num = berry / 8;remains = berry % 8;if (remains != 0)page_num ++;elsepage_num = page_num;printf("there are %d page total %d items",page_num, berry);int i = -1;while (1){char flag;if ((berry + i*8) >= 0){printf("(%d~%d)\n", (berry + i*8), (berry + (i+1)*8)); i_print_history(PRT_LEN, i);printf("@@@\n");while ('\n' == (flag = getchar())){}switch (flag){case 'p' :i--;break;case 'n' :break;}if (i >= 0){printf("have at the end!\n");printf("return to menu!\n");}}else{printf("(1~%d)\n", remains);i_print_history(remains, 0);printf("#########over##############\n"); return(0);}}return(0);}/* end:chat_history*//* start:menu*/int menu(){sleep(1);printf("----------help----menu---------\n");printf("\t r--report to user\n");printf("\t c--chat history\n");printf("\t h--help menu\n");printf("\t e--exit the system\n");printf("----------help_menu---------\n");int command = 0;printf("input command>");command = getchar();switch(command){case 'c':read_chat_history();break;case 'e':exit_sys();break;case 'r'://report();//break;default :menu();break;}getchar();return(0);}/* end:menu*/int main(){init();pid_t pid;switch (pid = fork()){case -1 :perror("fork error\n");exit(1);break;case 0 :return(0);}代码三:#include "i.h"#define START_PORT 8089struct sockaddr_in my_addr;int my_id;int my_log();/* declare funtion*//* */int i_send_msg(){int id;struct msg the_msg;char end = '@';printf("input recver id:");scanf("%d", &id);getchar();printf("\ninput content:");i_input(the_msg.content);char flag = 'y';if (1){the_msg.flag = 1;the_msg.id_from = my_id;the_msg.id_to = id;i_sendto(sockfd, &the_msg, sizeof(struct msg), 0, (struct sockaddr*)&server, sizeof(struct sockaddr)); i_saveto_chat(&the_msg); /* save to history */printf("send to id:%d success.\n", my_id);return(0);}elsereturn(1);return(0);}int reply(){return(0);}int send_file(){return(0);}/**//* start:initialize */int init(){struct ifreq req;struct sockaddr_in *host;int port;i_init();/* init user addr */bzero(&my_addr, sizeof(struct sockaddr));my_addr.sin_family = AF_INET;host = (struct sockaddr_in*)&(req.ifr_addr);printf("ip: %s\n", inet_ntoa(host->sin_addr));memcpy(&my_addr, (struct sockaddr_in*)&(req.ifr_addr), sizeof(struct sockaddr_in));port = START_PORT;do{port++;my_addr.sin_port = htons(port);bind(sockfd, (struct sockaddr*)&my_addr,sizeof(struct sockaddr));}while (errno == EADDRINUSE);struct chat_history apple;memset(&apple, 'b', HSTR_LEN);i_lseek(mainfd, 0, SEEK_SET);apple.count = 0;i_write(mainfd, &apple, HSTR_LEN);i_lseek(mainfd, -HSTR_LEN, SEEK_END);i_read(mainfd, &apple, HSTR_LEN);count = apple.count;printf("port:%d\n", port);printf("init successful\n");return(0);}/* end:initialize *//* start:chat_history*/int get_page_size(){struct chat_history page_size_reader;i_lseek(mainfd, -HSTR_LEN, SEEK_END);i_read(mainfd, &page_size_reader, HSTR_LEN);return(page_size_reader.count);}int read_chat_history(){printf("****char*history***");printf("(n-nextpage; p-prepage; q-quit)\n");int page_num;/* */int remains;int berry = get_page_size();page_num = berry / 8;remains = berry % 8;if (remains != 0)page_num ++;elsepage_num = page_num;printf("there are %d page total %d items",page_num, berry);int i = -1;if ((berry + i*8) >= 0){printf("(%d~%d)\n", (berry + i*8), (berry + (i+1)*8)); i_print_history(PRT_LEN, i);printf("@@@\n");while ('\n' == (flag = getchar())){}switch (flag){case 'p' :i--;break;case 'n' :i++;break;case 'q' :return(0);default :break;}if (i >= 0){printf("have at the end!\n");printf("return to menu!\n");}}else{printf("(1~%d)\n", remains);i_print_history(remains, 0);printf("#########over##############\n");return(0);}}return(0);}/* end:chat_history*//* start:exit_sys*/void exit_sys(){close(sockfd);close(mainfd);kill(0, SIGABRT);exit(0);}/* end:exit_sys*//* start:menu*/int print_menu(){printf("\n--------------help--menu----------------\n");printf("\t h--help munu\n");printf("\t s--send message\n");printf("\t r--reply to\n");printf("\t c--chat history\n");printf("\t f--send files\n");printf("\t e--exit the system\n");printf("----------------help--menu----------------\n");}int get_input(char *command){printf(">");scanf("%c", command);return(1);}int menu()/* to avoid the output at mixed with the sub process */sleep(1);print_menu();char command;while (1 == get_input(&command)){switch(command){case 'h':print_menu();break;case 's':i_send_msg();break;case 'r':reply();break;case 'f':send_file();break;case 'c':read_chat_history();break;case 'e':exit_sys();break;default :printf(">");break;}}return(0);}/* end:menu*//* start:message contol :send_msg and recv_msg */int ordnary_msg_recv(struct msg *pmsg){char time_info[25];char end_symble;end_symble = '&';/* handle the msg */printf("Message:from %s(id%d) to U:\n", pmsg->append, pmsg->id_from); i_print(pmsg->content, MSG_LEN);printf("\n\t%s", i_get_time());return(0);}int file_msg_recv(struct msg *pmsg){}int handle_msg(struct msg *pmsg){if (pmsg->flag == 1){ordnary_msg_recv(pmsg);return(0);}else if (pmsg->flag >= 4){file_msg_recv(pmsg);return(0);}return(0);}int listen_msg(){struct msg msg_recv;struct sockaddr addr_recv;int len = ADDR_LEN;printf("begin listen...\n");for ( ; ; ){i_recvfrom(sockfd, &msg_recv, MSG_LEN, 0,&addr_recv, &len);i_saveto_chat(&msg_recv); /* save to history */ordnary_msg_recv(&msg_recv);}}/* end:message contol*//* start:log process :login and regist */int login(){/* input id:*/printf("*****login>>\n");printf("id:");scanf("%d", &my_id);/* input password*/char password[15];printf("\npassword(*less 15 char):");scanf("%s", password);getchar();/* send login information */struct msg log_msg;bzero(&log_msg, MSG_LEN);log_msg.flag = 2;log_msg.id_from = my_id;log_msg.id_to = 0;strncpy(log_msg.content, password, 15);i_saveto_chat(&log_msg); /* save to history */i_sendto(sockfd, (struct msg*)&log_msg, MSG_LEN, 0, (struct sockaddr*)&server, sizeof(struct sockaddr));//printf("log_msg : %d\n", log_msg.id_from);//printf("password: %s\n", log_msg.content);/* after input msg ,wait for server respond*/struct sockaddr in_addr;int len = ADDR_LEN;i_recvfrom(sockfd, (struct msg*)&log_msg, MSG_LEN,0, &in_addr, &len);if (2 == log_msg.flag){printf("login success\n");return(0);}else{printf("login error:%s\n", log_msg.content);printf("please relog..\n");menu();}return (0);}int regist(){printf("*****regist>>\n");/* input chat name */char name[10];bzero(name, 10);printf("input your chat name(less 8 char):");scanf("%s", name);//name[9] = ';'; /* add a ; symbol in the end of name */ /* input password */char password[15];bzero(password, 15);printf("\ninput your password(less 14 char):");scanf("%s", password);/* send regist information*/struct msg reg_msg;bzero(®_msg, MSG_LEN);reg_msg.flag = 3;reg_msg.id_from = 0;reg_msg.id_to = 0;bzero(reg_msg.content, CNTNT_LEN);strncpy(reg_msg.content, name, 10);strncpy(&(reg_msg.content[10]), password, 15);reg_msg.content[25] = '\n';i_saveto_chat(®_msg); /* save to history *//* send regist informatin to server */i_sendto(sockfd, (struct msg*)®_msg, sizeof(struct msg), 0, (struct sockaddr*)&server, ADDR_LEN);/* after input msg ,wait for server respond*/printf("wating for server reply...\n");struct sockaddr in_addr;struct msg msg_back;int len = ADDR_LEN;bzero(&in_addr, ADDR_LEN);bzero(&msg_back, MSG_LEN);i_recvfrom(sockfd,(struct msg*)&msg_back, MSG_LEN,0,&in_addr, &len);/* check whether pass */if (3 != msg_back.flag){printf("error: %s \n", msg_back.content);exit(1);}elsemy_id = msg_back.id_to;printf("congratulate! you have regist""id %s(id %d) success\n", msg_back.content, msg_back.id_to); login();return(0);}int my_log(){/* choose login or regist*/char flag;printf("are you want login or regist(l/r)\n");scanf("%c", &flag);getchar();switch (flag){case 'l' :login();break;case 'r' :regist();break;default :printf("error input\n");my_log();break;}return (0);}/* end:log */int main(){init();printf("\n************welcome!************\n");my_log();pid_t pid;switch (pid = fork()){case -1 :perror("fork error!\n");exit(1);break;case 0 :listen_msg();break;default :menu();break;}}希望本⽂所述对⼤家实现linux多⼈聊天室程序。
Python基于Socket实现简易多人聊天室的示例代码
Python基于Socket实现简易多⼈聊天室的⽰例代码前⾔套接字(Sockets)是双向通信信道的端点。
套接字可以在⼀个进程内,在同⼀机器上的进程之间,或者在不同主机的进程之间进⾏通信,主机可以是任何⼀台有连接互联⽹的机器。
套接字可以通过多种不同的通道类型实现:Unix域套接字,TCP,UDP等。
套接字库提供了处理公共传输的特定类,以及⼀个⽤于处理其余部分的通⽤接⼝。
socket模块:要创建套接字,必须使⽤套接字模块中的socket.socket()函数,该函数具有⼀般语法s = socket.socket (socket_family, socket_type, protocol = 0)参数描述socket_family它的值可以是:AF_UNIX或AF_INET,如前所述。
socket_type它的值可以是:SOCK_STREAM或SOCK_DGRAM。
protocol这通常被省略,默认为0。
常⽤⽅法:序⽅法描述号1s.bind()此⽅法将地址(主机名,端⼝号对)绑定到套接字。
2s.recvfrom()此⽅法接收UDP消息,返回值是⼀对(字节,地址),其中字节是代表接收到的数据的字节对象,⽽地址是发送数据的套接字的地址3s.sendto()此⽅法发送UDP消息,将数据发送到套接字。
该套接字不应连接到远程套接字,因为⽬标套接字是由address指定的4s.close()此⽅法关闭套接字,套接字对象上所有以后的操作都将失败。
远端将不再接收任何数据(在清除排队的数据之后)。
套接字在被垃圾回收时会⾃动关闭5socket.gethostname()返回主机名,返回⼀个字符串,其中包含当前正在执⾏Python解释器的计算机的主机名。
⽰例1服务器端#sever.pyimport sockets = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)host = socket.gethostname()port = 8088s.bind((host,port))try:while True:receive_data,addr = s.recvfrom(1024)print("来⾃服务器" + str(addr) + "的消息:")print(receive_data.decode('utf-8'))msg = input('please input send to msg:')s.sendto(msg.encode('utf-8'),addr)except:s.close()客户端#client.pyimport sockets = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)try:while True:host = socket.gethostname()port = 8088send_data = input('please input msg:')s.sendto(send_data.encode('utf-8'),(host,port))msg,addr = s.recvfrom(1024)print("来⾃服务器" + str(addr) + "的消息:")print(msg.decode('utf-8'))except:s.close()服务端⽰例客户端⽰例简易的UDP聊天实现了,下⾯我们来优化⼀下⽰例。
linux中的socket编程
linux中的socket编程linux socket编程,不限于linux,⼀切皆socket“⼀切皆Socket!”话虽些许夸张,但是事实也是,现在的⽹络编程⼏乎都是⽤的socket。
——有感于实际编程和开源项⽬研究。
我们深谙信息交流的价值,那⽹络中进程之间如何通信,如我们每天打开浏览器浏览⽹页时,浏览器的进程怎么与web服务器通信的?当你⽤QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠socket?那什么是socket?socket的类型有哪些?还有socket 的基本函数,这些都是本⽂想介绍的。
本⽂的主要内容如下:1、⽹络中进程之间如何通信?2、Socket是什么?3、socket的基本操作3.1、socket()函数3.2、bind()函数3.3、listen()、connect()函数3.4、accept()函数3.5、read()、write()函数等3.6、close()函数4、socket中TCP的三次握⼿建⽴连接详解5、socket中TCP的四次握⼿释放连接详解6、⼀个例⼦(实践⼀下)、⽹络中进程之间如何通信?本地的进程间通信(IPC)有很多种⽅式,但可以总结为下⾯4类:消息传递(管道、FIFO、消息队列)同步(互斥量、条件变量、读写锁、⽂件和写记录锁、信号量)共享内存(匿名的和具名的)远程过程调⽤(Solaris门和Sun RPC)但这些都不是本⽂的主题!我们要讨论的是⽹络中进程之间如何通信?⾸要解决的问题是如何唯⼀标识⼀个进程,否则通信⽆从谈起!在本地可以通过进程PID来唯⼀标识⼀个进程,但是在⽹络中这是⾏不通的。
其实TCP/IP协议族已经帮我们解决了这个问题,⽹络层的“ip地址”可以唯⼀标识⽹络中的主机,⽽传输层的“协议+端⼝”可以唯⼀标识主机中的应⽤程序(进程)。
这样利⽤三元组(ip地址,协议,端⼝)就可以标识⽹络的进程了,⽹络中的进程通信就可以利⽤这个标志与其它进程进⾏交互。
Linux下简单的socket通信实例
Linux下简单的socket通信实例Linux下简单的socket通信实例If you spend too much time thinking about a thing, you’ll never get it done.—Bruce Lee学习⽹络编程也⼀段时间了,刚开始看《UNIX⽹络编程》的时候,觉得这本厚厚的书好难啊!看到后来,发现并没有想象中的那么难。
如果你是新⼿,建议你看到第⼆部分结束后,开始着⼿写代码。
不写代码肯定是不⾏的。
看100遍也没有敲⼀遍实现⼀遍来的清楚。
敲完以后,带着问题去看书,你会更加有针对性。
提⾼的速度是飞快的,这也是学习任何⼀本书、⼀门语⾔的唯⼀⼿段。
写这个博客也是因为刚开始学的时候,查了好多别⼈写的东西,百度了以后,发现⼤家只是把所有的代码⼀贴。
并没有讲解每个函数的功能。
我甚⾄不知道哪个函数是哪个头⽂件下的。
造成我对函数很不理解。
下⾯我会对每个函数的功能,和它的头⽂件以及函数原型写出来,让⼤家参考,第⼀次写博客,有什么错误的地⽅,希望⼤家指正。
可以在下⾯给我留⾔,也是我继续写下去的动⼒。
我很希望和⼤家⼀起分享学习⽹络编程遇到的种种困难与不顺,也希望和⼤家⼀起讨论其中遇到的问题,⼀起成长,如果你刚开始打算学习⽹络编程,那这篇⽂章⼀定能给你⼀些帮助。
我的邮箱:cvmimi_linhai@,转载请注明出处:/yusenwu/p/4579167.html。
关于怎样介绍这个简单的实例:(基本上涵盖了《UNIX⽹络编程》1-5章的内容,更深,更细的,需要我们再细读这本书)--> 1、代码展⽰,功能介绍 --> 2、⾸先介绍⼀下客户端和服务端中函数的功能以及函数的原形。
--> 3、关于连接三次握⼿和TCP连接关闭时候的分组交换--> 4、IPv4、IPv6套接字的地址结构 --> 5、⼀些好的学习⽹站总结 --> 6、代码下载 --> 7、总结 --> 8、实现⼀个echo的实例,代码可以到Github上下载client.c1 #include <stdio.h>2 #include <sys/socket.h>3 #include <sys/types.h>4 #include <stdlib.h>5 #include <netinet/in.h>6 #include <errno.h>7 #include <string.h>8 #include <arpa/inet.h>9 #include <unistd.h>10#define MAXLINE 102411int main(int argc,char **argv)12 {13char *servInetAddr = "127.0.0.1";14int socketfd;15struct sockaddr_in sockaddr;16char recvline[MAXLINE], sendline[MAXLINE];17int n;1819if(argc != 2)20 {21 printf("client <ipaddress> \n");22 exit(0);23 }2425 socketfd = socket(AF_INET,SOCK_STREAM,0);26 memset(&sockaddr,0,sizeof(sockaddr));27 sockaddr.sin_family = AF_INET;28 sockaddr.sin_port = htons(10004);29 inet_pton(AF_INET,servInetAddr,&sockaddr.sin_addr)30if((connect(socketfd,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) < 0 )31 {31 printf("connect error %s errno: %d\n",strerror(errno),errno);32 exit(0);33 }3435 printf("send message to server\n");3637 fgets(sendline,1024,stdin);3839if((send(socketfd,sendline,strlen(sendline),0)) < 0)40 {41 printf("send mes error: %s errno : %d",strerror(errno),errno);42 exit(0);43 }4445 close(socketfd);46 printf("exit\n");47 exit(0);48 }-执⾏:gcc client.c -o client 后启动 ./client 客户端程序启动前先启动./server-----------------------------------------server.c1 #include <stdio.h>2 #include <sys/socket.h>3 #include <sys/types.h>4 #include <string.h>5 #include <netinet/in.h>6 #include <stdlib.h>7 #include <errno.h>8 #include <unistd.h>9 #include <arpa/inet.h>1011#define MAXLINE 102412int main(int argc,char **argv)13 {14int listenfd,connfd;15struct sockaddr_in sockaddr;16char buff[MAXLINE];17int n;1819 memset(&sockaddr,0,sizeof(sockaddr));2021 sockaddr.sin_family = AF_INET;22 sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);23 sockaddr.sin_port = htons(10004);2425 listenfd = socket(AF_INET,SOCK_STREAM,0);2627 bind(listenfd,(struct sockaddr *) &sockaddr,sizeof(sockaddr));2829 listen(listenfd,1024);303132 printf("Please wait for the client information\n");3334for(;;)35 {36if((connfd = accept(listenfd,(struct sockaddr*)NULL,NULL))==-1)37 {38 printf("accpet socket error: %s errno :%d\n",strerror(errno),errno);39continue;40 }4142 n = recv(connfd,buff,MAXLINE,0);43 buff[n] = '\0';44 printf("recv msg from client:%s",buff);45 close(connfd);46 }47 close(listenfd);48 }-执⾏:gcc server.c -o server 后启动 ./server 服务端程序-------------------------------------------------------> 1、代码展⽰,功能介绍 上⾯这个简单的socket通信的代码要实现的功能:从客户端发送⼀条消息后,服务端接收这条消息,并在服务端显⽰(recv msg from client:****)。
用Socket的编程机制实现网上交谈
I,aa e b gic ds okt w ihi ue ee pten t okcm nct npoeue a ,h a e po e i otegn r rc P Jv . t a l e S ces hc sdt dv l e r o mu i i rcd r f t ipp r rb sn eea su — n nu , s O o h w ao sT s t h lt
t r a e n S c e o u e b sd o o k t mmu iai n p o e u eo v h o g h n tn em o e. e g n rlc mmu iai n s f ae c n b e eo e ae c nct r cd r fa atru hteis c d 1 o I a Th e ea o nc t o t r a e d v l p d b s d o w
on t i o ,O t e ei e ti ee e evaue hs neS h r sc ran rf rnc l ,
Ke r slv ;e o kS c e;o ywo d ; an t r ;o k t mmu iain a w c nc t o
1引 言
在 Jv aa中 Sce 可 以 理 解 为 客 户 端 或 服务 器端 的 一 个 特 殊 okt 对 象 , 于 T PI 基 C/ P协 议 建 立 有 连 接 的通 信 。可 以 形 象 的认 为 通 信 就 是 打 电话 的 过 程 . 个 S ce 通 信 无 论 功 能 多 么 齐 全 、 序 多 一 okt 程
网络 通 信 程 序 。 通过 实例 模 型探 讨 基 于 I a的 S ce 通信 程序 的一 般 结 构 。 对 开发 一 般 性 的通 信 软件 , 一 定 的 参 考价 值 。 a v o kt 有
基于socket的简单聊天室的设计与实现
基于socket的简单聊天室的设计与实现作者:周留军武金磊来源:《电脑知识与技术·学术交流》2008年第21期摘要:介绍了在Linux上用socket编程来设计并实现一个简单聊天室。
首先选择了服务器的轮询工作方式,以满足多个用户进程的连接;然后从数据结构、模块开发和源码实现三个方面详细分析了聊天室的实现;最后将该聊天室与传统聊天室进行了比较,并指出该聊天室的优势所在。
关键词:聊天室; Linux ;socket ;数据结构中图分类号:TP393文献标识码:A文章编号:1009-3044(2008)21-30442-03The Design and Accomplishment of the Simple Chat-room Based on SocketZHOU Liu-jun1,2, WU Jin-lei1(1.College of Information and Electrical Engineering of CUMT, Xuzhou 221008,China;2.Xuzhou Institute of Architectural Technology, Xuzhou 221008 China)Abstract: How to design and accomplish a simple chat room with socket in linux is introduced is introduced in this paper. In order to meet many connections of user process, the poll woking of server is selected firstly. Then accomplishment of the simple chat-room is analyzed particularly in the facets of data structure, module development and codeaccomplishment. According to the comparison of the chat room and the traditional chat room, advantage of the chat room is shown.Key words: chat room; linux; socket; data structure1 引言Socket聊天室与传统的CGI聊天室工作原理有很大的不同,其基本原理是抛开OGI和WWW服务器,根据HTML规范,接收到浏览器的请求以后,模仿WWW服务器的响应,将聊天内容发回浏览器。
基于linux下网络聊天室的设计与实现
本聊天室系统采用了c/s形式。服务器主要是处理客户输入信息。首先要存储客户的个人资料,相当于注册。再有,在客户的聊天信息时,也要记录下客户的聊天记录,已备查看聊天记录所用。当然,服务器还有自己的动态数据处理。客户状态分为链接客户和非连接客户,我采用结构体存储链接客户信息,以链表来记录链接客户。而链接客户又分为登陆客户和未登陆客户,这就通过修改链表上客户的名字。当客户一链接客户服务端时,就给客户一个账号,也就是相当于注册信息,同时并发服务器一直在为连接用户创建线程,系统的总设计框图如下:
1.2
1、Linux作为一个开源的操作系统利于使用人员交流学习而且Linux 的许多特性有利于网络编程。首先,Linux系统拥有许多网络编程的库函数,可以方便地实现客户机/ 服务器模型。其次Linux 秉承了UNIX 的设备无关性这一优秀特征,即它通过文件的描述符实现了统一的设备接口,网络的Socket数据传输是一种特殊的I/ 0 Scoket 也是一种文件描述符。再有,且其内核小、效率高、兼容性好和稳定性强等优点。
第二章 linux网络聊天室设计思想
2.1
本系统是想在linux系统下实现一个聊天室系统,只要有服务器和客户端。它具备的基本功能包括注册、登陆、一对一私聊、查看在线人数等。
1、服务器端:负责处理用户发来的各种信息,管理用户的动作(注册、登陆、一对一私聊、查看在线人数)和管理用户的信息。
2、客户端:主要用于查看在线人数、发送信息给特定用户等功能,
Keywords:TCP / IP; the linux; the socke
第一章:绪论
1ቤተ መጻሕፍቲ ባይዱ1
网络编程就是通过使用套接字来达到进程间通信目的编程。网络编程可以做如下工作:网络安全,通讯设备研发,协议分析,网络管理系统等。单就网络编程来说,linux和windows其实都差不多,只是基于不同的开发平台,并且linux的API基本上是自己用C写的,而windows底层有封装,只要熟悉linux网络编程,如果以后转windows相对容易。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux下的Socket网络编程:一个简易聊天室的实现-徐慧军
高级程序设计与应用实践
报告
一个简易聊天室的实现
姓名:徐慧军
学号:2121134
专业:电子与通信工程
学院:信息科学与技术学院
任课教师:廖晓飞
2013年05月02日
Linux下的Socket网络编程:
——一个简易聊天室的实现一、socket介绍
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函数原型为:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:调用成功,返回socket文件描述符;失败,返回-1,并设置errno 参数说明:
domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP 协议族;
type参数指定socket的类型:
SOCK_STREAM 提供有序、可靠、双向及基于连接的字节流
SOCK_DGRAM 支持数据报
SOCK_SEQPACKET 提供有序、可靠、双向及基于连接的数据报通信
SOCK_RAW 提供对原始网络协议的访问
SOCK_RDM 提供可靠的数据报层,但是不保证有序性
protocol通常赋值"0".
socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。
调用socket函数时,socket执行体将建立一个socket,实际上"建立一个socket"意味着为一个socket数据结构分配存储空间。
socket执行体为你管理描述符表。
两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。
socket数据结构中包含这五种信息。
三、Socket邦定
bind函数原型为:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sock_fd,struct sockaddr *my_addr, int addrlen);
功能说明:将套接字和指定的端口相连。
成功返回0,否则,返回-1,并置errno.
参数说明:sock_fd是调用socket函数返回的socket描述符,
my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
addrlen常被设置为sizeof(struct sockaddr)。
struct sockaddr结构类型是用来保存socket信息的:
struct sockaddr {
unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 字节的协议地址 */
};
sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;
sa_data则包含该socket的IP地址和端口号。
另外还有一种结构类型:
struct sockaddr_in {
short int sin_family; /* 地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP地址 */
unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */
};
这个结构更方便使用。
sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。
指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:
my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */
my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */
通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。
同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。
注意在使用bind函数是需要将sin_port和sin_addr转换成为网络字节优先顺序。
计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先(大端和小端)。
Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。