热门标签 | 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.




推荐阅读
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 摘要: 在测试数据中,生成中文姓名是一个常见的需求。本文介绍了使用C#编写的随机生成中文姓名的方法,并分享了相关代码。作者欢迎读者提出意见和建议。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
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社区 版权所有