热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

socketprogrammingexample

1.头文件viserver.h头文件注册信号处理函数intcatch_signal(intsig,void(*handler)(int));从socket读数据到char*b
1. 头文件
vi server.h 

// 头文件
// 注册信号处理函数
int catch_signal(int sig, void (*handler) (int));
// 从socket读数据到char *buf
int read_in(int socket, char *buf, int len);
// 错误函数, 当exit_val=0只输出错误信息, 不退出程序. 其他值输出错误信息并退出程序
void error(char * msg, int exit_val);
// 创建监听socket
int open_listener_socket();
// 绑定socket到端口port
void bind_to_port(int socket, int port);
// 监听socket, 允许队列数queue.
void listen_to_socket(int socket, int queue);
// 开始等待客户端连接.
int accept_socket(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// 向socket发送信息
int say(int socket, char *s);
// 信号处理函数
void handle_shutdown(int sig);


2. c文件
vi server.c

#include
#include
#include
#include
#include
#include
#include
#include
#include "server.h"int catch_signal(int sig, void (*handler) (int)) {struct sigaction action;action.sa_handler = handler;sigemptyset(&action.sa_mask);// sigemptyset() return 0 on success and -1 on error.action.sa_flags = 0;return sigaction(sig, &action, NULL);// sigaction() returns 0 on success and -1 on error.
}// recv()注意:
// 1. The characters are not terminated with a \0 character.
// 2. When someone types text in telnet, the string always ends \r\n.
// 3. The recv() will return the number of characters, or –1 if there's an error, or
// 0 if the client has closed the connection.
// 4. You're not guaranteed to receive all the characters in a single call to recv().// This reads all the characters until it reaches '\n'.
int read_in(int socket, char *buf, int len) {char *s &#61; buf;int slen &#61; len;int c &#61; recv(socket, s, slen, 0);// Keep reading until there are no more characters or you reach &#39;\n&#39;.while ( (c > 0) && (s[c-1] !&#61; &#39;\n&#39;) ) {s &#43;&#61; c; slen -&#61; c;c &#61; recv(socket, s, slen, 0);}if (c <0)// In case there&#39;s an errorreturn c;else if (c &#61;&#61; 0)// Nothing read; send back an empty stringbuf[0] &#61; &#39;\0&#39;;else// Replace the last character(here is &#39;\n&#39;) with a &#39;\0&#39;.s[c-1] &#61; &#39;\0&#39;;return len-slen;
}void error(char * msg, int exit_val) {fprintf(stderr, "%s: %s\n", msg, strerror(errno));// if exit_val &#61;&#61; 0, not exit the program.if (exit_val)exit(exit_val);
}int open_listener_socket() {// Create an Internet streaming socket.int s &#61; socket(PF_INET, SOCK_STREAM, 0);if (s &#61;&#61; -1)error("Can&#39;t open socket", 1);return s;
}void bind_to_port(int socket, int port) {struct sockaddr_in name;name.sin_family &#61; PF_INET;name.sin_port &#61; (in_port_t) htons(port);name.sin_addr.s_addr &#61; htonl(INADDR_ANY);// Yes, reuse the socket (so you can restart the server without problems).int reuse &#61; 1;if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(int)) &#61;&#61; -1)error("Can&#39;t set the reuse option on the socket", 1);int c &#61; bind(socket, (struct sockaddr *) &name, sizeof(name));if(c &#61;&#61; -1)error("Can&#39;t bind to socket", 1);
}void listen_to_socket(int socket, int queue) {int l &#61; listen(socket, queue);if(l &#61;&#61; -1)error("Can&#39;t listen", 1);
}// wait client connect to this server. return the secondary socketfd.
int accept_socket(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {int connect_d &#61; accept(sockfd, addr, addrlen);if (connect_d &#61;&#61; -1)error("Can&#39;t open secondary socket", 1);return connect_d;
}// Send a string to a client.
int say(int socket, char *s) {int result &#61; send(socket, s, strlen(s), 0);if(result &#61;&#61; -1)// when error don&#39;t exit.error("Error talking to the client", 0);return result;
}// This will store the main listener socket for the server.
int listener_d;// If someone hits Ctrl-C when the server is running,
// this function will close the socket before the program ends.
void handle_shutdown(int sig) {if(listener_d)close(listener_d);fprintf(stderr, "Signal:%i, Bye!\n", sig);exit(0);
}int main(int argc, char *argv[]) {int port;int queue;char opt;// get option argumentwhile ((opt &#61; getopt(argc, argv, "hp:q:")) !&#61; EOF) {switch(opt) {case &#39;h&#39;:fprintf(stdout, "%s -p $port_num -q $queue_num\n", argv[0]);exit(1);case &#39;p&#39;:port &#61; atoi(optarg);break;case &#39;q&#39;:queue &#61; atoi(optarg);break;default:fprintf(stderr, "Unknown option: %s\n", optarg);return 1;}}// if argument count is not 5, exit main function.if(argc !&#61; 5) {fprintf(stdout, "%s -p $port_num -q $queue_num\n", argv[0]);return 1;}// 注册SIGINT 到信号处理函数handle_shutdown.if(catch_signal(SIGINT, handle_shutdown) &#61;&#61; -1)error("Can&#39;t set the interrupt handler", 1);// 打开一个data stream socket.listener_d &#61; open_listener_socket();// 绑定到端口portbind_to_port(listener_d, port);// 监听, 并指定queue长度listen_to_socket(listener_d, queue);// 准备接收客户端连接struct sockaddr_storage client_addr;unsigned int address_size &#61; sizeof(client_addr);puts("Waiting for connection");char buf[255];// accept_socket等待客户端连接.while(1) {// accept将创建the secondary socketfd.int connect_d &#61; accept_socket(listener_d, (struct sockaddr *) &client_addr, &address_size);// 子进程处理客户端请求if ( !fork() ) {close(listener_d);if (say(connect_d, "Internet Knock-Knock Protocol Server\r\nVersion 1.0\r\nKnock! Knock!\r\n> ") !&#61; -1) {read_in(connect_d, buf, sizeof(buf));}if (strncasecmp("Who&#39;s there?", buf, 12))say(connect_d, "You should say &#39;Who&#39;s there?&#39;!");else {if (say(connect_d, "Oscar\r\n> ") !&#61; -1) {read_in(connect_d, buf, sizeof(buf));if (strncasecmp("Oscar who?", buf, 10))say(connect_d, "You should say &#39;Oscar who?&#39;!\r\n");elsesay(connect_d, "Oscar silly question, you get a silly answer\r\n");}}// 子进程处理完请求后关闭the secondary socketfd. 并退出.close(connect_d);exit(0);}// 主进程不与客户端继续交互, 所以直接关闭the secondary socketfd. 继续while循环, 等待客户端连接.close(connect_d);}return 0;
}

2. 编译, 执行.

[root&#64;db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -I. -g ./server.c -o server
[root&#64;db-172-16-3-150 zzz]# ./server -h
./server -p $port_num -q $queue_num
[root&#64;db-172-16-3-150 zzz]# ./server -p 30000 -q 10 // 因为本例用子进程处理客户端请求, 主进程及时的close(connect_d), 所以这个queue不需要太大. 0就可以了.
Waiting for connection


其他会话1 : 

[root&#64;db-172-16-3-150 zzz]# telnet 172.16.3.150 30000
Trying 172.16.3.150...
Connected to db-172-16-3-150.sky-mobi.com (172.16.3.150).
Escape character is &#39;^]&#39;.
Internet Knock-Knock Protocol Server
Version 1.0
Knock! Knock!
> hello
You should say &#39;Who&#39;s there?&#39;!Connection closed by foreign host.


其他会话2 : 

[root&#64;db-172-16-3-150 zzz]# telnet 172.16.3.150 30000
Trying 172.16.3.150...
Connected to db-172-16-3-150.sky-mobi.com (172.16.3.150).
Escape character is &#39;^]&#39;.
Internet Knock-Knock Protocol Server
Version 1.0
Knock! Knock!
> Who&#39;s there?
Oscar
> Oscar who?
Oscar silly question, you get a silly answer
Connection closed by foreign host.


【注意】

1. NAMElisten - listen for connections on a socketSYNOPSIS#include int listen(int sockfd, int backlog);
NOTESThe behaviour of the backlog parameter on TCP sockets changed with Linux 2.2. Now it specifies the queuelength for completely established sockets waiting to be accepted, instead of the number of incomplete connec-tion requests. The maximum length of the queue for incomplete sockets can be set using the tcp_max_syn_backlogsysctl. When synCOOKIEs are enabled there is no logical maximum length and this sysctl setting is ignored.See tcp(7) for more information.




推荐阅读
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • 在本文中,我们将为 HelloWorld 项目添加视图组件,以确保控制器返回的视图路径能够正确映射到指定页面。这一步骤将为后续的测试和开发奠定基础。首先,我们将介绍如何配置视图解析器,以便 SpringMVC 能够识别并渲染相应的视图文件。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • 使用 `git stash` 可以将当前未提交的修改保存到一个临时存储区,以便在后续恢复工作目录时使用。例如,在处理中间状态时,可以通过 `git stash` 命令将当前的所有未提交更改推送到一个新的储藏中,从而保持工作目录的整洁。此外,本文还将详细介绍如何解决 `git stash pop` 时可能出现的冲突问题,帮助用户高效地管理代码变更。 ... [详细]
  • JavaScript XML操作实用工具类:XmlUtilsJS技巧与应用 ... [详细]
  • 本文详细介绍了如何在Java Web服务器上部署音视频服务,并提供了完整的验证流程。以AnyChat为例,这是一款跨平台的音视频解决方案,广泛应用于需要实时音视频交互的项目中。通过具体的部署步骤和测试方法,确保了音视频服务的稳定性和可靠性。 ... [详细]
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • 在分析Socket服务器程序接收中文数据时出现的乱码问题时,我们发现客户端使用C#编写的数据在返回时能够正常显示。本文详细探讨了该问题的成因,并提出了一种有效的解决方案。通过调整字符编码设置和优化数据传输格式,确保了中文数据在传输过程中的完整性与正确性。具体实现代码包括对Socket读取事件的处理,确保数据以正确的编码格式进行解析和显示。 ... [详细]
  • 在C#中开发MP3播放器时,我正在考虑如何高效存储元数据以便快速检索。选择合适的数据结构,如字典或数组,对于优化性能至关重要。字典能够提供快速的键值对查找,而数组则在连续存储和遍历方面表现优异。根据具体需求,合理选择数据结构将显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文全面解析了 gRPC 的基础知识与高级应用,从 helloworld.proto 文件入手,详细阐述了如何定义服务接口。例如,`Greeter` 服务中的 `SayHello` 方法,该方法在客户端和服务器端的消息交互中起到了关键作用。通过实例代码,读者可以深入了解 gRPC 的工作原理及其在实际项目中的应用。 ... [详细]
  • 本文探讨了如何在C#应用程序中通过选择ComboBox项从MySQL数据库中检索数据值。具体介绍了在事件处理方法 `comboBox2_SelectedIndexChanged` 中可能出现的常见错误,并提供了详细的解决方案和优化建议,以确保数据能够正确且高效地从数据库中读取并显示在界面上。此外,还讨论了连接字符串的配置、SQL查询语句的编写以及异常处理的最佳实践,帮助开发者避免常见的陷阱并提高代码的健壮性。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
author-avatar
傻孩纸黄国帅哟
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有