计算机网络学习socket--day3
1.REUSEADDR(地址重复利用)
1.REUSEADDR解决服务器关闭后重新绑定地址,在day3中知道服务器端必须绑定地址
2.服务器端尽可能使用REUSEADDR
3.在绑定之前尽可能调用setsockopt来设置REUSEADDR套接字选项
4.使用REUSEADDR选项可以使得不必等待TIME_WAIT状态消失就可以重启服务器
man setsockopt
2.处理多客户连接(process-per-conection)
一个连接一个进程来处理并发
服务器处于监听状态,每次连接一个客户端创建一个进程
||---------------------------------------------------------------------
服务器
#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);
}
}
close(conn);
}
int main(void)
{
int listenfd;
if((listenfd = 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 = htonl(INADDR_ANY);
int on = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
ERR_EXIT("setsockopt");/*实现地址重复利用,这样可以使服务器关闭后不用等待TIME_WAIT消失后在重新启动服务器,而可以直接启动服务器*/
if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))) < 0
ERR_EXIT("bind");
if(listen(listenfd, SOMAXCONM) < 0)
ERR_EXIT("listen");
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int coon;
pid_t pid;
while(1)
{
if((coon = accept(listen,(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<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
int main(void)
{
int sock;
if((listenfd = 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");
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
{
write(sock,sendbuf,strlen(sendbuf));
read(sock,recvbuf,sizeof(recvbuf));
fputs(recvbuf,stdout);
memset(sendbuf,0,sizeof(sendbuf));
memset(recvbuf,0,sizeof(recvbuf));
}
close(sock);
return 0;
}
||------------------------------------------------------------
3.点对点聊天程序
先开服务器端,在开客户端
当客户端或者服务器端关闭后父进程关闭但是子进程还没有关闭可以通过信号来实现
#include<signal.h>
man 2 kill
||---------------------------------------------------------------------
实现p2p的服务的服务器
||------------------------------------------------------------
#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>
#include<signal.h>
void handler(int sig)
{
printf("recv a sig=%d\n",sig);
exit(EXIT_SUCCESS);
}
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
int main(void)
{
int listenfd;
if((listenfd = 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 = htonl(INADDR_ANY);
if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))) < 0
ERR_EXIT("bind");
if(listen(listenfd, SOMAXCONM) < 0)
ERR_EXIT("listen");
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(peeraddr);
int coon;
if((coon = accept(listen,(struct sockaddr*)&peeraddr,&peerlen)) < 0)
ERR_EXIT("accept");
printf("ip=%d 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);/*借助SIGUSR1信号关联一个kill*/
char sendbuf[1024] = {0};
while (fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
{
write(conn,sendbuf,strlen(sendbuf));
memset(sendbuf, 0, sizeof(sendbuf)); //清空缓冲区,以便第二次输出不会只覆盖一部分
}
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);
}
kill(pid,SIGUSR1);
exit(EXIT_SUCCESS);
}
return 0;
}
||------------------------------------------------------------
实现p2p的服务的客户端
#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>
#include<signal.h>
void handler(int sig)
{
printf("recv a sig=%d\n",sig);
exit(EXIT_SUCCESS);
}
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
int main(void)
{
int sock;
if((listenfd = 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); //当大于0,把接收到是数据输出
}
close(sock);
kill(pid, 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;
}
||---------------------------------------------------------------------
计算机网络学习socket--day3的更多相关文章
- 【总结】学习Socket编写的聊天室小程序
1.前言 在学习Socket之前,先来学习点网络相关的知识吧,自己学习过程中的一些总结,Socket是一门很高深的学问,本文只是Socket一些最基础的东西,大神请自觉绕路. 传输协议 TCP:Tra ...
- Spark菜鸟学习营Day3 RDD编程进阶
Spark菜鸟学习营Day3 RDD编程进阶 RDD代码简化 对于昨天练习的代码,我们可以从几个方面来简化: 使用fluent风格写法,可以减少对于中间变量的定义. 使用lambda表示式来替换对象写 ...
- python学习------socket编程
一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视频 ...
- 在Android手机上学习socket程序
我们都知道Android手机是基于Linux系统的,在没有Linux环境,但是想学习socket编程的同学可以在Android手机中试试,利用ndk编译可执行文件在Android手机中运行.不同于动态 ...
- [转] 3个学习Socket编程的简单例子:TCP Server/Client, Select
以前都是采用ACE的编写网络应用,最近由于工作需要,需要直接只用socket接口编写CS的代码,重新学习这方面的知识,给出自己所用到的3个简单例子,都是拷贝别人的程序.如果你能完全理解这3个例子,估计 ...
- 深入学习socket网络编程,以java语言为例
了解java的socket编程与Linux Socket API之间的关系 一.java的网络编程 1.socket原理 socket通信就是通过IP和端口号将两台主机建立连接,提供通信.主机A的应用 ...
- 计算机网络学习笔记NO.2 物理层
2.1 基本概念 2.1.1 物理层概念 物理层解决如何在连接各种计算机的传输媒体上传输数据比特流,而不是指具体的传输媒体. 物理层主要任务:确定与传输媒体接口有关的一些特性(定义标准) 机械特性:定 ...
- MFC学习 socket
下面未处理异常 tcpserver.cpp #include "WinSock2.h" #include <stdio.h> #pragma comment(lib, ...
- python网络爬虫与信息提取 学习笔记day3
Day3: 只需两行代码解析html或xml信息 具体代码实现:day3_1 注意BeautifulSoup的B和S需要大写,因为python大小写敏感 import requests r ...
随机推荐
- numpy.stack和numpy.concatenate的区别
在使用numpy进行矩阵运算的时候踩到的坑,原因是不能正确区分numpy.concatenate和numpy.stack在功能上的差异. 先说numpy.concatenate,直接看文档: nump ...
- JSR133提案-修复Java内存模型
目录 1. 什么是内存模型? 2. JSR 133是关于什么的? 3. 再谈指令重排序 4.同步都做了什么? 5. final字段在旧的内存模型中为什么可以改变? 6."初始化安全" ...
- SQL中游标的使用示例
declare @email_source varchar(MAX); --1.原始发件人字段 declare @key_name varchar(50); --2.我方卷号或客户代码 declare ...
- cb47a_c++_STL_算法_排列组合next_prev_permutation
cb47a_c++_STL_算法_排列组合next_prev_permutation 使用前必须先排序.必须是 1,2,3或者3,2,1.否者结果不准确.如果, 1,2,4,6.这样数据不会准确nex ...
- 5种经典的Linux桌面系统
最近一直在准备Linux相关的PPT,对于一个老码农来说Linux系统自然是比较熟悉了,随口可以说出好几种Linux的版本,然而对于计算机初学者可能就知道windows操作系统.也许你告诉他你可以安装 ...
- Spring IoC component-scan 节点详解
前言 我们在了解 Spring 容器的扩展功能 (ApplicationContext) 之前,先介绍下 context:component-scan 标签的解析过程,其作用很大是注解能生效的关键所在 ...
- sublime清空控制台
解决方法 – 只需运行print('\n'*100)打印100个换行符,您将无法看到任何以前的输出,除非你向上滚动一些距离.
- js语法基础入门(7)
7.数组 7.1.什么是数组以及相关概念? 什么是数组?是一组数据有序排列的集合.将一组数据按一定顺序组织为一个组合,并对这个组合命名,这样便构成了数组. 什么是数组元素?组成数组的每一个数据称为数组 ...
- SpringBoot项目部署到tomcat
SpringBoot部署到tomcat 一.修改maven.xml 1.添加<.packaging>war</.packaging>,打包为war包 <packaging ...
- php抽奖功能
在项目开发中经常会遇到花钱抽奖类型的需求.但是老板总是担心用户用小钱抽到大奖.这样会导致项目亏损.下边这段代码可以有效制止抽奖项目亏钱. 个人奖池: 语言:thinkphp redis mysql 表 ...