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 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...
随机推荐
- nginx+c+cgi开发
http://blog.csdn.net/marising/article/details/3932938 1.Nginx 1.1.安装 Nginx 的中文维基 http://wiki.codemon ...
- Java Super 覆盖方法
子类从父类中继承方法,有时候,子类需要修改父类中定义的方法的实现,这称作方法覆盖. 比如,GeometricObject类中的toString方法返回表示集合对象的字符串,这个方法就可以被覆盖,返回表 ...
- js基础知识(pomelo阅读)
0,node.js调试: http://www.noanylove.com/2011/12/node-the-inspector-debugging-node-js/ 1,读取配置文件: var ...
- Java-->List&Set
一.List集合 特点:有序可重复 List集合的猜想: 1.每个元素是不是应该有序号 index 2.addFirst.addLast.set(intdex, 对象) 3.get(index)... ...
- 160. Intersection of Two Linked Lists
Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...
- 带同时滚动小色条的banner轮播图jq
<div class="baoliao tongcheng"> <p class="headline1">同城<font>活 ...
- HDU 4686 矩阵快速幂 Arc of Dream
由式子的性质发现都是线性的,考虑构造矩阵,先有式子,a[i] = ax * a[i-1] + ay; b[i] = bx*b[i-1] +by; a[i]*b[i] = ax*bx*a[i-1]*b[ ...
- Oracle数据库Linux下的导入IMP
和相关篇的EXP相对应的用了如下的导入方法. [oracle@localhost ~]$ imp Import: Release 11.2.0.1.0 - Production on Fri Sep ...
- 信頼済みサイト对window.open窗体大小影响原因之一
如果某站点被添加进去之后,这个站点窗体限制被决定了,window.open里面,status bar 无效的设置不再起作用.而且,如果原来status bar被 任务栏挡住的话,这个时候它就会被显示出 ...
- js部分---表单验证;(含正则表达式)
1.非空验证 <div>用户名:<input id="yhm" type="text" name="yhm" />& ...