Linux 高级网络编程
设置套接字函数:
- #include<sys/socket.h>
- int setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t* optlen);
- //sockfd要设置的目的套接字
- //level套接字的控制层次
- //optname optval optlen是三个相关的参数,通过不同的搭配可以设置不同的功能
应用:
1.数据收发时限设置
- struct timeva timeout;
- timeout.tv_sec=5;
- timeout.tv_usec=0;
- //接受时限
- setsockopt(serversocket, SQL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout));
- //发送时限
- setsockopt(serversocket, SQL_SOCKET,SO_SNDTIMEO, (char*)&timeout,sizeof(timeout));
2.修改收发缓冲区
- //接收缓冲区
- int opt=1024*1024;
- setsockopt(serversocket, SQL_SOCKET, SO_RCVBUF, (const char*)&opt,sizeof(opt));
- //发送缓冲区
- setsockopt(serversocket, SQL_SOCKET, SO_SNDBUF, (const char*)&opt,sizeof(opt));
3.广播设置
- int bBroadcast=1;
- setsockopt(seversocket, SQL_SOCKET, SO_BROADCAST,(cosnt char*)&bBroadcast,sizeof(bBroadcast));
4.直接数据复制
为了提升系统性能,在发送或接受数据时,可以主动设置数据不经历由缓冲区到套接字缓存区的拷贝。
- int opt=0;
- setsockopt(serversocket, SQL_SOCKET,SO_SNDBUF,(char*)&opt,sizeof(opt));
- setsockopt(serversocket, SQL_SOCKET,SO_RCVBUF,(char*)&opt,sizeof(opt));
Select技术:
- #include <stdio.h>
- #include <sys/socket.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <string.h>
- #define SERVER_PORT 5555
- #define QUEUE_LENGTH 5
- #define BUF_SIZE 200
- int main(int argc, char **argv)
- {
- int server_socket,new_socket;
- struct sockaddr_in server_addr,client_addr;
- socklen_t sin_size;
- int client_socket[QUEUE_LENGTH];
- int conn_num;
- int yes=1;
- char buf[BUF_SIZE];
- int ret;
- int i;
- //创建套接字
- if((server_socket=socket(AF_INET,SOCK_STREAM,0))<0){
- perror("Socket");
- return 0;
- }
- //设置为可重复使用
- if(setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1){
- perror("setsockopt");
- return 0;
- }
- //设置服务器地址信息设置
- server_addr.sin_family=AF_INET; //TCP
- server_addr.sin_port=htons(SERVER_PORT);
- server_addr.sin_addr.s_addr=INADDR_ANY; //本地IP地址
- memset(server_addr.sin_zero,'\0',sizeof(server_addr.sin_zero));
- //绑定套接字与地址信息
- if(bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1){
- perror("setsockopt");
- return 0;
- }
- //侦听
- if(listen(server_socket,5)==-1){
- perror("setsockopt");
- return 0;
- }
- printf("listen port : %d\n",SERVER_PORT);
- fd_set clientfdset;
- int maxsock;
- struct timeval tv;
- conn_num=0;
- sin_size=sizeof(client_addr);
- maxsock=server_socket;
- while(1){
- //初始化,清空并添加服务器套接字到集合
- FD_ZERO(&clientfdset);
- FD_SET(server_socket,&clientfdset);
- //设置超时时间
- tv.tv_sec=15;
- tv.tv_usec=0;
- //添加连接的客户端到集合
- for(i=0;i<QUEUE_LENGTH;i++){
- if(client_socket[i]!=0)
- FD_SET(client_socket[i],&clientfdset);
- }
- //select模式
- ret=select(maxsock+1,&clientfdset,NULL,NULL,&tv);
- if(ret<0){
- perror("select");
- break;
- }
- else if(ret==0){
- printf("waiting timeout\n");
- continue;
- }
- //检查集合内是否已经存在
- for(i=0;i<conn_num;i++){
- if(FD_ISSET(client_socket[i],&clientfdset)){
- ret=recv(client_socket[i],buf,sizeof(buf),0);
- if(ret<=0){
- printf("client[%d] close\n",i);
- close(client_socket[i]);
- FD_CLR(client_socket[i],&clientfdset);
- client_socket[i]=0;
- }
- else{
- printf("client[%d] msg: %s\n",i,buf);
- send(client_socket[i],buf,sizeof(buf),0);
- }
- }
- }
- if(FD_ISSET(server_socket,&clientfdset)){
- new_socket=accept(server_socket,(struct sockaddr*)&client_addr,&sin_size);
- if(new_socket<=0){
- perror("accept");
- continue;
- }
- if(conn_num<QUEUE_LENGTH){
- client_socket[conn_num++]=new_socket;
- printf("new client[%d] %s: %d\n",conn_num,inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
- if(new_socket>maxsock)
- maxsock=new_socket;
- }
- else{
- send(new_socket,"sorry overload!",sizeof("sorry overload!"),0);
- close(new_socket);
- break;
- }
- }
- }
- for(i=0;i<QUEUE_LENGTH;i++){
- if(client_socket[i]!=0)
- close(client_socket[i]);
- }
- }
原始套接字技术:
原始套接字是一种套接字底层技术,它工作在网络层。利用原始套接字可以完成如下功能。
- 设置网卡为混杂模式,嗅探当前网路流经本网卡的所有数据包。
- 构造各种数据包(IP,ICMP,TCP,UDP等),并进行发送。
- 进行新协议的验证。
原始套接字可用于木马中的通信模块,伪造IP地址,拒绝服务攻击,数据包嗅探。
原始套接字的创建:
- int rawsock=socket(AF_INET, SOCK_RAW, htons(ETH_P_IP));
- //可以获取IP层的所有数据报文
htons参数的可选值及其意义
协议码 | 协议名 |
IPPROTO_ICMP | ICMP协议 |
ETH_P_IP | IP协议 |
IPPROTO_TCP | TCP协议 |
IPPROTO_UDP | UDP协议 |
IPPROTO_IPV6 | IPv6协议 |
IPPROTO_EGP | EGP协议 |
数据发送:
在原始套接字中,执行数据发送前要条用setsocketopt函数进行套接字的首部设定:
- int opt;
- setsockopt(sockfd,IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt));
例子:
- //利用原始套接字实现一个简单的采集网络数据包,并进行反向解析IP,MAC地址
#include <stdio.h>- #include <sys/socket.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <linux/if_ether.h>
- #include <linux/in.h>
- #define BUFFER_MAX 2048
- int main(int argc, char **argv)
- {
- int rawsock;
- char buffer[BUFFER_MAX];
- char *ethhead;
- char *iphead;
- char *phead;
- //创建原始套接字
- if((rawsock=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP)))<0){
- printf("error:create raw socket!\n");
- exit(0);
- }
- long framecount =0;
- while(1){
- int readnum = recvfrom(rawsock,buffer,2048,0,NULL,NULL);
- if(readnum<42){
- printf("error:header is incomplete!\n");
- exit(0);
- }
- ethhead=(char*)buffer;
- phead=ethhead;
- int ethernetmask=0XFF;
- framecount++;
- printf("---------------AnalysisiPacket[%d]---------------\n",framecount);
- printf("MAC:");
- int i=6;
- for(;i<=11;i++)
- printf("%.2X:",phead[i]ðernetmask);
- printf("------->");
- for(i=0;i<=5;i++)
- printf("%.2X:",phead[i]ðernetmask);
- printf("\n");
- iphead=ethhead+14;
- phead=iphead+12;
- printf("IP:");
- for(i=0;i<=3;i++){
- printf("%d",phead[i]ðernetmask);
- if(i!=3)
- printf(".");
- }
- printf("------->");
- for(i=4;i<=7;i++){
- printf("%d",phead[i]ðernetmask);
- if(i!=7)
- printf(".");
- }
- printf("\n");
- int prototype=(iphead+9)[0];
- phead=iphead+20;
- printf("Protocol:");
- switch(prototype){
- case IPPROTO_ICMP:
- printf("ICMP\n");
- break;
- case IPPROTO_IGMP:
- printf("IGMP\n");
- break;
- case IPPROTO_IPIP:
- printf("IP");
- break;
- case IPPROTO_TCP:
- printf("TCP|source port: %u |",(phead[0]<<8)&0XFF00|phead[1]&0XFF);
- printf("destport: %u\n",(phead[2]<<8)&0XFF00|phead[3]&0XFF);
- break;
- case IPPROTO_UDP:
- printf("UDP|source port: %u |",(phead[0]<<8)&0XFF00|phead[1]&0XFF);
- printf("destport: %u\n",(phead[2]<<8)&0XFF00|phead[3]&0XFF);
- break;
- case IPPROTO_RAW:
- printf("RAW\n");
- break;
- default:
- printf("Unkown\n");
- }
- printf("-----------------end--------------------");
- }
- return 0;
- }
广播技术:
ARP(Address Resolution Protocol)和NTP(Network Time Protocol)都属于广播通信。
ARP是局域网中的地址解析协议,利用这个协议,可以找出IP地址到MAC地址的映射关系。当主机A准备与主机B通信时,如果只知道主机B的IP地址,则主机A向整个全网发送一个ARP请求,询问IP地址为XXXX的主机,如果主机B收到就会产生回应。
NTP是网络时间协议。在支持广播的局域网中设置NTP协议,可以使NTP服务器每隔一个固定的时间间隔,就向全网发送时间信息,客户端在收到时间信息后进行更新处理。
原理解析:
要进行广播通信,首先要理解广播地址。在IP地址中,如果最后一个数字是255,则一定是一个广播地址。
- 网络广播地址:网络广播地址在没有进行子网划分的网络内广播,由于当强的网络均涉及子网划分,故此种地址很少存在
- 受限广播地址:以255.255.255.255组成的广播地址,在当前路由器均不转发此类广播
- 子网广播地址:子网广播地址是一种常用的广播方式,它是指在一个具体的子网内进行广播,比如192.168是网络ID,那么192.168.1.255就是子网192.168.1的广播
- 全部子网广播地址:是指所有子网络的广播,以上一个为例,全部子网广播地址是192.168.255.255
广播要采用UDP的方式,具体流程如下:
- 创建UDP套接字
- 设置套接字属性为SO_BROADCAST,设置为广播地址
- 设置广播地址为INADDR_BROADCAST,同时也要指定发送端口
- 进行数据收发操作
例子:
- //bserver.c
- #include <sys/types.h>
- #include <stdio.h>
- #include <sys/socket.h>
- #include <stdlib.h>
- #include <string.h>
- #include <netdb.h>
- #include <errno.h>
- #define BUFFSIZE 200
- #define PORT 5050
- int main(int argc, char **argv)
- {
- int serversocket;
- struct sockaddr_in serveraddress,clientaddress;
- int so_broadcast=1;
- if((serversocket=socket(AF_INET,SOCK_DGRAM,0))<0){
- perror("socket");
- return 0;
- }
- if(setsockopt(serversocket,SOL_SOCKET,SO_BROADCAST,&so_broadcast,sizeof(so_broadcast))<0){
- perror("setsockopt");
- return 0;
- }
- serveraddress.sin_family=AF_INET;
- serveraddress.sin_port=htons(INADDR_ANY);
- serveraddress.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- if(bind(serversocket,(struct sockaddr*)&serveraddress,sizeof(struct sockaddr))<0){
- perror("bind");
- return 0;
- }
- clientaddress.sin_family=AF_INET;
- clientaddress.sin_port=htons(PORT);
- clientaddress.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- while(1){
- char buf[BUFFSIZE];
- printf("please input your word:");
- scanf("%s",buf);
- if(sendto(serversocket,buf,strlen(buf),0,(struct sockaddr*)&clientaddress,sizeof(clientaddress))<0){
- perror("sendto");
- return 0;
- }
- else
- printf("send msg: %s\n",buf);
- }
- return 0;
- }
- //bclient.c
- #include <sys/types.h>
- #include <stdio.h>
- #include <sys/socket.h>
- #include <stdlib.h>
- #include <string.h>
- #include <netdb.h>
- #include <errno.h>
- int main(int argc, char **argv)
- {
- int clientsocket;
- struct sockaddr_in serveraddress,clientaddress;
- clientsocket=socket(AF_INET,SOCK_DGRAM,0);
- serveraddress.sin_family=AF_INET;
- serveraddress.sin_port=htons(5050);
- serveraddress.sin_addr.s_addr=htonl(INADDR_ANY);
- int opt=1;
- if(setsockopt(clientsocket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0){
- perror("setsockopt");
- return 0;
- }
- if(bind(clientsocket,(struct sockaddr*)&serveraddress,sizeof(struct sockaddr))!=0){
- perror("bind");
- return 0;
- }
- char buf[200];
- while(1){
- memset(buf,0,200);
- int size=0;
- size=recvfrom(clientsocket,buf,200,0,(struct sockaddr*)&serveraddress,sizeof(serveraddress));
- buf[size]='\0';
- printf("IP:%s msg:%s\n",inet_ntoa(clientaddress.sin_addr),buf);
- if(strcmp(buf,"quit")==0){
- printf("system quit!\n");
- close(clientsocket);
- return 0;
- }
- }
- return 0;
- }
组播技术:
组播可以实现小范围内的互联,在发送者和每一个接受者之间时间点对多点的网络连接,是广播通信的一种变种。
根据IP地址的规定,D类地址为组播地址,其网络号为固定的1110,第4到31位定义了某一特殊的组播地址,范围为244.0.0.0~239.255.255.255。其中244.0.0.0~244.0.0.255的地址,它们大多是为了特殊的目的保留的,不建议使用。
套接字的基本属性:组播参数对应5个参数,通过setsockopt设置
- //加入组播
- int setsockopt(client_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&multiaddress,sizeof(multiaddress))
- //退出组播
- int setsockopt(client_socket,IPPROTO_IP,IP_DROP_MEMBERSHIP,&multiaddress,sizeof(multiaddress))
- //这里有一个重要的参数multiaddress,结构:
- struct ip_mreq{
- struct in_addr imr_multiaddr; //组播地址
- struct in_addr imr_interface; //IPv4地址
- }
主要流程:
- 服务器端设置一个多播地址,创建一个多播组。
- 客户端指定多播地址,加入多播。
- 程序结束后,退出多播。
例子:
- //memberServer.c
- #include <stdio.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- int main(int argc, char **argv)
- {
- int server_socket;
- struct sockaddr_in address;
- //创建UDP
- server_socket=socket(AF_INET,SOCK_DGRAM,0);
- if(server_socket<0){
- perror("socket");
- return 0;
- }
- //初始化多播地址
- memset(&address,0,sizeof(address));
- address.sin_family=AF_INET;
- address.sin_port=htons(5555);
- address.sin_addr.s_addr=inet_addr("224.0.1.100");
- //发送信息
- while(1){
- char buf[200];
- printf("input your word:");
- scanf("%s",buf);
- if(sendto(server_socket,buf,sizeof(buf),0,(struct sockaddr*)&address,sizeof(address))<0){
- perror("sendto");
- return 0;
- }
- }
- return 0;
- }
- //memberClient.c
- #include <stdio.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- int main(int argc, char **argv)
- {
- struct ip_mreq mreq;
- int serveraddress_len;
- int client_socket;
- struct sockaddr_in serveraddress;
- //初始化地址
- memset(&serveraddress,0,sizeof(serveraddress));
- serveraddress.sin_family=AF_INET;
- serveraddress.sin_port=htons(5555);
- serveraddress.sin_addr.s_addr=htonl(INADDR_ANY);
- if((client_socket=socket(AF_INET,SOCK_DGRAM,0))<0){
- perror("client");
- return 0;
- }
- //绑定SOCKET
- if(bind(client_socket,(struct sockaddr*)&serveraddress,sizeof(serveraddress))<0){
- printf("bind");
- return 0;
- }
- int opt=1;
- if(setsockopt(client_socket,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))<0){
- printf("setsockopt1");
- return 0;
- }
- //加入多播
- mreq.imr_multiaddr.s_addr=inet_addr("244.0.1.100");
- mreq.imr_interface.s_addr=htonl(INADDR_ANY);
- if(setsockopt(client_socket,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){
- perror("setsockopt2");
- return 0;
- }
- while(1){
- char buf[200];
- serveraddress_len=sizeof(serveraddress);
- if(recvfrom(client_socket,buf,200,0,(struct sockaddr*)&serveraddress,(socklen_t *)serveraddress_len)<0){
- perror("recvfrom");
- }
- printf("msg from server: %s\n",buf);
- if(strcmp(buf,"quit")==0){
- if(setsockopt(client_socket,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq))<0){
- perror("setsokopt3");
- }
- close(client_socket);
- return 0;
- }
- }
- return 0;
- }
Linux 高级网络编程的更多相关文章
- 嵌入式linux的网络编程(1)--TCP/IP协议概述
嵌入式linux的网络编程(1)--TCP/IP协议概述 1.OSI参考模型及TCP/IP参考模型 通信协议用于协调不同网络设备之间的信息交换,它们建立了设备之间互相识别的信息机制.大家一定都听说过著 ...
- Linux C网络编程学习笔记
Linux C网络编程总结报告 一.Linux C 网络编程知识介绍: 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端:(client) 在网络程序中, ...
- Linux C++ 网络编程学习系列(1)——端口复用实现
Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...
- 【linux高级程序设计】(第十三章)Linux Socket网络编程基础 2
BSD Socket网络编程API 创建socket对象 int socket (int __domain, int __type, int __protocol) :成功返回socket文件描述符, ...
- 【linux高级程序设计】(第十三章)Linux Socket网络编程基础
IP地址定义: struct in_addr{ __u32 s_addr; }; in_addr_t inet_addr (__const char * __cp) :把点分十进制IP地址字符串转换 ...
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- 【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)
RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [ ...
- 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)
RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三 多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...
- 【Linux/unix网络编程】之使用socket进行TCP编程
实验一 TCP数据发送与接收 [实验目的] 1.熟练掌握套接字函数的使用方法. 2.应用套接字函数完成基本TCP通讯,实现服务器与客户端的信息交互. [实验学时] 4学时 [实验内容] 实现一个服务器 ...
随机推荐
- Sharepoint 2010 创建栏 计算栏
SharePoint 创建栏时,可以添加计算字段, 网上查了查,相关资料如下: http://wenku.baidu.com/view/936239e9b8f67c1cfad6b88f.html ht ...
- windows下如何对mysql进行整裤备份
通常情况下备份一个数据库,直接单裤备份即可,更完善一点的会要求做到定时单裤备份.然而很多时候又由于裤实例是在太多,这样会导致备份非常耗时,因而有时候需要对整个数据库应用进行备份.那么在windows下 ...
- 为eclipse设置好看的代码主题
eclipse的默认代码背景是白色,上个文章简单说了字体设置,这边主要介绍代码高亮的主题设置,打造更酷的编程界面.网上有文章说可以在设置里面逐一设置,但是比较麻烦,可以去网上下载现成的主题包,网址为: ...
- ssm操作控制台输出sql语句 log4j.properties
# Configures Log4j for Tomcat and Sakai # use "A" for log in with catalina.out (actually s ...
- Android Handler leak 分析及解决办法
In Android, Handler classes should be static or leaks might occur, Messages enqueued on the applicat ...
- CocoaPods报错及解决方法记录
[!] Oh no, an error occurred. Search for existing GitHub issues similar to yours: https://github.com ...
- 关于Java异常和错误的几个问题
1.Java中什么是Exception? 异常是Java传达给你的系统和程序错误的方式. 在java中,异常功能是通过实现比如Throwable,Exception,RuntimeException之 ...
- [杂]DeadLock, Isolation Level, EntityFramework
由于没有注意到EF事务的默认隔离级别是Serializable,(据说EF6.0以后默认隔离级别改成了Read_Commit_Snapshot)--这里有误,应该是加了TransactionScope ...
- GitHub在Visual Studio 2015中获得TFS/VSO同等地位
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 在Visual Studio 2015中微软为GitHub提供了扩展插件,从而让GitHub ...
- struts2文件下载及 <param name="inputName">inputStream</param>的理解
转自:http://blog.csdn.net/wnczwl369/article/details/7483290 转自:http://hi.baidu.com/c2_sun/item/934a542 ...