08socket编程
有个SO_REUSEADDR值得注意一下:

- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #define ERR_EXIT(m) \
- do \
- { \
- perror(m); \
- exit(EXIT_FAILURE); \
- } while(0)
- void do_service(int conn)
- {
- char recvbuf[1024];
- while (1)
- {
- memset(recvbuf, 0, sizeof(recvbuf));
- int ret = read(conn, recvbuf, sizeof(recvbuf));
- if (ret == 0) //服务器端要能捕捉到客户端的退出
- {
- printf("client close\n");
- break;
- }
- else if (ret == -1)
- ERR_EXIT("read");
- fputs(recvbuf, stdout);
- write(conn, recvbuf, ret);
- }
- }
- int main(void)
- {
- int listenfd;
- if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- /* if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)*/
- ERR_EXIT("socket");
- struct sockaddr_in servaddr;
- memset(&servaddr, 0, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(5188);
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
- /*inet_aton("127.0.0.1", &servaddr.sin_addr);*/
- //这个就是上边说的那个服务器重启的解决方法
- int on = 1;
- if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
- ERR_EXIT("setsockopt");
- if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
- ERR_EXIT("bind");
- if (listen(listenfd, SOMAXCONN) < 0)
- ERR_EXIT("listen");
- struct sockaddr_in peeraddr;
- socklen_t peerlen = sizeof(peeraddr);
- int conn;
- pid_t pid;
- while (1)
- {
- if ((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)
- ERR_EXIT("accept");
- printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
- pid = fork();
- if (pid == -1)
- ERR_EXIT("fork");
- if (pid == 0)
- {
- close(listenfd);//子进程只负责接收后的工作
- do_service(conn); //这里写了一个自定义的函数来解决子进程的操作
- exit(EXIT_SUCCESS);
- }
- else
- close(conn); //父进程只负责监听接受连接,不负责具体的操作。
- }
- return 0;
- }
其中还有很多的细节需要注意,大家亲自试一下,首先自己动手去写,自己试各种情况有什么问题,然后再回过头来看程序和自己写的差别,才会对细节的处理理解更深刻。
下面实现一个点对点的聊天程序:
服务器端:
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #define ERR_EXIT(m) \
- do \
- { \
- perror(m); \
- exit(EXIT_FAILURE); \
- } while(0)
- void handler(int sig)
- {
- printf("recv a sig=%d\n", sig);
- exit(EXIT_SUCCESS);
- }
- int main(void)
- {
- int listenfd;
- if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- /* if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)*/
- ERR_EXIT("socket");
- struct sockaddr_in servaddr;
- memset(&servaddr, 0, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(5188);
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
- /*inet_aton("127.0.0.1", &servaddr.sin_addr);*/
- int on = 1;
- if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
- ERR_EXIT("setsockopt");
- if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
- ERR_EXIT("bind");
- if (listen(listenfd, SOMAXCONN) < 0)
- ERR_EXIT("listen");
- struct sockaddr_in peeraddr;
- socklen_t peerlen = sizeof(peeraddr);
- int conn;
- if ((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)
- ERR_EXIT("accept");
- printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
- pid_t pid;
- pid = fork();
- if (pid == -1)
- ERR_EXIT("fork");
- if (pid == 0)
- {
- signal(SIGUSR1, handler); //这里用到了信号处理,在父进程退出的时候会发一个信号过来给子进程,然后子进程也跟着退出
- char sendbuf[1024] = {0};
- while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
- {
- write(conn, sendbuf, strlen(sendbuf));
- memset(sendbuf, 0, sizeof(sendbuf));
- }
- printf("child close\n");
- exit(EXIT_SUCCESS);
- }
- else
- {
- char recvbuf[1024];
- while (1)
- {
- memset(recvbuf, 0, sizeof(recvbuf));
- int ret = read(conn, recvbuf, sizeof(recvbuf));
- if (ret == -1)
- ERR_EXIT("read");
- else if (ret == 0)
- {
- printf("peer close\n");
- break;
- }
- fputs(recvbuf, stdout);
- }
- printf("parent close\n");
- kill(pid, SIGUSR1);//这是父进程退出前要向子进程发一个自定义的信号
- exit(EXIT_SUCCESS);
- }
- return 0;
- }
客户端:
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #define ERR_EXIT(m) \
- do \
- { \
- perror(m); \
- exit(EXIT_FAILURE); \
- } while(0)
- void handler(int sig)
- {
- printf("recv a sig=%d\n", sig);
- exit(EXIT_SUCCESS);
- }
- int main(void)
- {
- int sock;
- if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- ERR_EXIT("socket");
- struct sockaddr_in servaddr;
- memset(&servaddr, 0, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(5188);
- servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
- if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
- ERR_EXIT("connect");
- pid_t pid;
- pid = fork();
- if (pid == -1)
- ERR_EXIT("fork");
- if (pid == 0)
- {
- char recvbuf[1024];
- while (1)
- {
- memset(recvbuf, 0, sizeof(recvbuf));
- int ret = read(sock, recvbuf, sizeof(recvbuf));
- if (ret == -1)
- ERR_EXIT("read");
- else if (ret == 0)
- {
- printf("peer close\n");
- break;
- }
- fputs(recvbuf, stdout);
- }
- close(sock);
- kill(getppid(), SIGUSR1);
- }
- else
- {
- signal(SIGUSR1, handler);
- char sendbuf[1024] = {0};
- while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
- {
- write(sock, sendbuf, strlen(sendbuf));
- memset(sendbuf, 0, sizeof(sendbuf));
- }
- close(sock);
- }
- return 0;
- }
这一节信息量比较大,得好好消化一下。
08socket编程的更多相关文章
- python学习笔记08-- socket编程
本节内容: 一.网络基础知识 二.socket概念及相关语法 2.1socket概念 2.2socket解释 2.3socket模块功能介绍 2.4socket粘包问题 2.5Socket多并发 一. ...
- 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代
2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...
- JavaScript之父Brendan Eich,Clojure 创建者Rich Hickey,Python创建者Van Rossum等编程大牛对程序员的职业建议
软件开发是现时很火的职业.据美国劳动局发布的一项统计数据显示,从2014年至2024年,美国就业市场对开发人员的需求量将增长17%,而这个增长率比起所有职业的平均需求量高出了7%.很多人年轻人会选择编 ...
- 读书笔记:JavaScript DOM 编程艺术(第二版)
读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- C#异步编程(一)
异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...
- UE4新手之编程指南
虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...
- C#与C++的发展历程第三 - C#5.0异步编程巅峰
系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...
- 猫哥网络编程系列:HTTP PEM 万能调试法
注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...
随机推荐
- 论文学习 - 《Hadoop平台下的海量数据存储技术研究》
摘要 研究背景: 1. 互联网的图片数据急剧膨胀 2. Hadoop平台下的Hdfs分布式文件系统能够很好的处理海量数据 研究内容: 1. Hadoop平台工作原理 2. Hadoop平台下图片存储系 ...
- iOS7中如何去除UINavigationbar下边的那条黑线
做项目过程中遇到要去掉导航栏下面的一条黑线,从网上找到的一个方法 默认UINavigationbar样式 准备用于替换的背景 替换后的效果 if ([self.navigationController ...
- C++ Primer : 第十二章 : 文本查询程序
C++ Primer书上这个例子讲的很不错,写写帮助自己理解标准库和智能指针. .h 文件内容 #include <fstream> #include <iostream> # ...
- POJ 3461 裸的KMP
直接贴代码吧 #include<cstdio> #include<cstring> ],T[]; ]; int n,m; void getfail() { f[] = ; f[ ...
- Android 客户端和服务器 json交互
http://www.cnblogs.com/jyan/articles/2544974.html 1.JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. ...
- Java中将16进制字符串转换成汉字
技术交流群:233513714 /** * 将16进制字符串转换成汉字 * @param str * @return */ public static String deUnicode(String ...
- 黑马程序员——JAVA基础之程序控制流结构之循环结构,循环嵌套
------- android培训.java培训.期待与您交流! ---------- 循环结构: 代表语句:while ,do while ,for while语句格式 : while(条件表达式) ...
- caffe:编译时提示:unsupported GNU version! gcc versions later than 4.9 are not supported!
NVCC src/caffe/solvers/adam_solver.cuIn file included from /usr/local/cuda/include/cuda_runtime.h:76 ...
- C++面向对象要点
先说说面向对象思想的一个总体认识 对象通常会有行为,这些行为是靠信息支撑,这些信息包括外部信息和内部信息,对象行为会维护其中的一部分信息 因此对象可以看成是这样一种实体,它获取信息,然后决定自己的行为 ...
- KMP字符串模式匹配学习笔记
KMP算法实验 1.编程计算模式串(子串)的next值.2.利用KMP算法在主串中找到模式串的位置. 参考代码:---------int getNexlVal( char * s, int j)// ...