经验大分享:Socket网络编程

简介: 经验大分享:Socket网络编程

  上一小节我们讲了使用select来避免使用多进程的资源浪费问题。上次只是实现了从多个客户端发送数据给服务器端,接下来就要实现从服务器端发送数据给各个客户端。

  使用select多路转换处理聊天程序2

  client.c 使用上一节用的那个,在那个基础上修改下面几句

66 //send-recv 一些返回指没有判断,具体可以看server.c

67 if((pid=fork())[span style="color: rgba(128, 0, 128, 1)">0)

68 {

69 perror("fork error\n");

70 }

71 else if(pid==0)/child/

72 {

73 while(1)

74 {

75 fgets(sendBuf,MAX_BUF,stdin);

76 if(send(sockfd,sendBuf,strlen(sendBuf),0)==-1)

77 {

78 perror("fail to receive datas.");

79 }

80 memset(sendBuf,0,sizeof(sendBuf));

81 }

82 }

83 else

84 {

85 while(1)

86 {

87 if((recvSize=recv(sockfd,recvBuf,MAX_BUF,0)==-1))

88 {

89 printf("Server maybe shutdown!");

90 break;

91 }

92 printf("Server:%s\n",recvBuf);

93 memset(recvBuf,0,sizeof(recvBuf));

94 }

95 kill(pid,SIGKILL);

96 }

97

98 close(sockfd);

99

100

101 return 0;

102 }

  server.c 我们在上一小节的基础上加上一个处理服务器stdin读取数据,然后遍历所有fd_A里面还连接着的客户端,然后一个一个的发送数据。

111 while(1)

112 {

113 FD_ZERO(servfd);//清空所有server的fd

114 FD_ZERO(recvfd);//清空所有client的fd

115 FD_SET(sockfd,servfd);

116 //timeout.tv_sec=30;//可以减少判断的次数

117 switch(select(max_servfd+1,servfd,NULL,NULL,timeout))

118 {

          ...

141 //代码效果参考:http://www.zidongmutanji.com/bxxx/564212.html

}

142 //FD_COPY(recvfd,servfd);

143 for(i=0;i

144 {

145 if(fd_A【i】!=0)

146 {

147 FD_SET(fd_A【i】,recvfd);

148 }

149 }

150

151 switch(select(max_recvfd+1,recvfd,NULL,NULL,timeout))

152 {

          ...182 }

183

184 /用于检测stdin是否有数据/

185 FD_ZERO(servfd);

186 FD_SET(STDIN_FILENO,servfd);

187

188 switch(select(STDIN_FILENO+1,servfd,NULL,NULL,timeout))

189 {

190 case -1:

191 break;

192 case 0:

193 break;

194 default:

195 /send datas to client/

196 if(FD_ISSET(STDIN_FILENO,servfd))

197 {

198 //代码效果参考:http://www.zidongmutanji.com/bxxx/37488.html

fgets(sendBuf,MAX_DATA_SIZE,stdin);

199 for(i=0;i

200 {

201 if(fd_A【i】!=0)

202 {

203 printf("数据发往%d,",fd_A【i】);

204 if((sendSize=send(fd_A【i】,sendBuf,strlen(sendBuf),0))!=strlen(sendBuf))

205 {

206 perror("fail");

207 exit(1);

208 }

209 else

210 {

211 printf("Success\n");

212 }

213 }

214 }

215 memset(sendBuf,0,MAX_DATA_SIZE);

216 fflush(stdin);

217 }

218 break;

219 }

220 }

221 return 0;

222 }

  废话不多说,直接上运行时的截图

  程序运行的顺序是,运行server,然后运行client1,server发送data1,client2连接server,server发送data2,client3连接server,server发送data3,此时client1退出连接,server获取fd 4 close,发送data4的时候没有发送给fd4。然后client4连接上去。分配为fd7。(虽然fd4已经关闭了,按说可以给client4分配fd4,不过太麻烦我这里就没有实现。)

  实现聊天室功能

  接下来就是实现聊天室功能。上面server.c中有三个select,第一个是处理随时可能来的客户端连接,第二个select是处理随时可能从客户器端来的数据,第三个select是处理随时可能从控制台输入数据,并send到各个客户端。要实现聊天室功能,就对第二个和第三个select进行合并。具体不多说,直接上代码

  client.c 基本不变

  server.c

1 #include

   ...

36 int main(int argc,char argv【】)

37 {

    ...

111 while(1)

112 {

113 FD_ZERO(servfd);//清空所有server的fd

114 FD_ZERO(recvfd);//清空所有client的fd

115 FD_SET(sockfd,servfd);

116 //timeout.tv_sec=30;//可以减少判断的次数

117 switch(select(max_servfd+1,servfd,NULL,NULL,timeout))

118 {

119 ...

141 }

       ...

151 switch(select(max_recvfd+1,recvfd,NULL,NULL,timeout))

152 {

153 case -1:

154 //select error

155 break;

156 case 0:

157 //timeout

158 break;

159 default:

160 for(i=0;i

161 {

162 if(FD_ISSET(fd_A【i】,recvfd))

163 {

164 /receive datas from client/

165 if((recvSize=recv(fd_A【i】,recvBuf,MAX_DATA_SIZE,0))==-1 || recvSize==0)

166 {

167 //perror("fail to receive datas");

168 //表示该client是关闭的

169 printf("fd %d close\n",fd_A【i】);

170 FD_CLR(fd_A【i】,recvfd);

171 fd_A【i】=0;

172 }

173 else//客户端发送数据过来,然后这里进行转发

174 {

175 /send datas to client*/

176 for(j=0;j

177 {

178 if(fd_A【j】!=0i!=j)

179 {

180 printf("数据发往%d,",fd_A【j】);

181 if((sendSize=send(fd_A【j】,recvBuf,strlen(recvBuf),0))!=strlen(recvBuf))

182 {

183 perror("fail");

184 exit(1);

185 }

186 else

187 {

188 printf("Success\n");

189 }

190 }

191 }

192 //可以判断recvBuf是否为bye来判断是否可以close

193 memset(recvBuf,0,MAX_DATA_SIZE);

194 }

195 }

196 }

197 break;

198 }

199 }

200 return 0;

201 }

  直接上运行时图片

  各个程序运行的循序是先运行server,然后运行client1,client2,然后cli1发送数据data1,此时cli2接收到server发来的转发数据,然后... ...

  好了,到现在为止已经完成了聊天室功能了,还可以随时进入随时出来。好像还不错的样子。下一节就介绍引入用户名登陆的字符界面(由于我不会图形化界面,所以就不花时间去学那个了,至于字符界面下有个curses.h据说可以弄得很好看,我这里就不弄了。有兴趣的可以去弄一下),还有一些人性化的中文提示,然后整理一下代码。由于基本没有什么技术含量,所以如果到时候篇幅不够就再加个数据库设计,考虑使用数据库来保存用户(为了方便就使用mysql吧)。

  小小剧透一下,如果接下来有时间将会实现以下功能 用户功能,指令功能,私聊功能,vip功能,文件发送功能,多服务器问题

  本文地址:

作者:无脑仔的小明

出处:

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。

相关文章
|
2天前
|
开发者 Python
Python Socket编程:不只是基础,更有进阶秘籍,让你的网络应用飞起来!
在数字时代,网络应用成为连接世界的桥梁。Python凭借简洁的语法和丰富的库支持,成为开发高效网络应用的首选。本文通过实时聊天室案例,介绍Python Socket编程的基础与进阶技巧。基础篇涵盖服务器和客户端的建立与数据交换;进阶篇则探讨多线程与异步IO优化方案,助力提升应用性能。通过本案例,你将掌握Socket编程的核心技能,推动网络应用飞得更高、更远。
17 1
|
28天前
|
网络协议 安全 网络安全
网络编程:基于socket的TCP/IP通信。
网络编程:基于socket的TCP/IP通信。
129 0
|
8天前
|
网络协议 安全 网络安全
震惊!Python Socket竟能如此玩转网络通信,基础到进阶全攻略!
【9月更文挑战第12天】在网络通信中,Socket编程是连接不同应用与服务的基石。本文通过问答形式,从基础到进阶全面解析Python Socket编程。涵盖Socket的重要性、创建TCP服务器与客户端、处理并发连接及进阶话题如非阻塞Socket、IO多路复用等,帮助读者深入了解并掌握网络通信的核心技术。
25 6
|
6天前
|
网络协议 Linux 应用服务中间件
Socket通信之网络协议基本原理
【9月更文挑战第14天】网络协议是机器间交流的约定格式,确保信息准确传达。主要模型有OSI七层与TCP/IP模型,通过分层简化复杂网络环境。IP地址全局定位设备,MAC地址则在本地网络中定位。网络分层后,数据包层层封装,经由不同层次协议处理,最终通过Socket系统调用在应用层解析和响应。
|
7天前
|
消息中间件 网络协议 网络安全
解锁Python Socket新姿势,进阶篇带你玩转高级网络通信技巧!
【9月更文挑战第13天】在掌握了Python Socket编程基础后,你是否想进一步提升技能?本指南将深入探讨Socket编程精髓,包括从阻塞到非阻塞I/O以提高并发性能,使用`select`进行非阻塞操作示例;通过SSL/TLS加密通信保障数据安全,附带创建SSL服务器的代码实例;以及介绍高级网络协议与框架,如HTTP、WebSocket和ZeroMQ,帮助你简化复杂应用开发。通过学习这些高级技巧,你将在网络编程领域更进一步。
21 2
|
1月前
|
分布式计算 网络协议 Python
Python网络编程:socket编程
Socket 编程是网络编程的重要部分,主要用于在不同计算机之间进行通信。Python 提供了一个非常强大的 socket 库,使得网络编程变得简单和灵活。本篇博文将详细介绍 Python 的 socket 编程,包括基础概念、核心组件、常用功能,并附上一个综合的示例及其运行结果。
|
1月前
|
网络协议 Java
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
这篇文章全面讲解了基于Socket的TCP网络编程,包括Socket基本概念、TCP编程步骤、客户端和服务端的通信过程,并通过具体代码示例展示了客户端与服务端之间的数据通信。同时,还提供了多个案例分析,如客户端发送信息给服务端、客户端发送文件给服务端以及服务端保存文件并返回确认信息给客户端的场景。
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
|
16天前
|
存储 网络协议 安全
C语言 网络编程(五)Socket和端口
Socket 是 TCP/IP 五层网络模型中应用层的编程接口,用于实现不同主机间应用程序的双向通信。它作为网络通信的端点,连接应用层与网络协议栈,提供可靠的流式或非流式数据传输服务。Socket 包括流式(SOCKET_STREAM)、数据报(SOCK_DGRAM)和原始套接字(SOCK_RAW)三种类型,分别适用于不同场景。通过 IP 地址和端口号,Socket 能准确识别并转发数据包至指定进程。端口号分为知名端口(1-1023)、注册端口(1024-49151)和动态端口(49152-65535),确保数据准确交付。
|
20天前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
42 0
|
20天前
|
Rust 网络协议 安全
揭开Rust网络编程的神秘面纱:全新的Socket体验,让你告别内存泄漏的噩梦!
【8月更文挑战第31天】Rust语言凭借其卓越的内存安全性和高性能,在网络编程领域展现出独特优势。本文将带你探索Rust中的Socket编程,展示如何使用标准库`std::net`模块轻松实现TCP服务器与客户端。通过简洁的代码示例,你将看到Rust如何简化网络通信流程,并通过`async/await`异步模型高效处理并发连接。此外,Rust社区提供的优秀库如`tokio`和`async-std`进一步增强了异步网络编程的能力。无论是从基础示例还是高级应用,Rust都将为你带来耳目一新的网络编程体验。
60 0