Linux下Socket编程详解

合集下载

linux socket编程基础(必读)

linux  socket编程基础(必读)
void bzero(void * s,int n):将参数 s 指定的内存的前 n 个字节设置 为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int n):从参数 src 指定 的内存区域拷贝指定数目的字节内容到参数 dest 指定的内存区域。
在调用函数 connect 之前,客户机需要指定服务器进程的套接字地址。客户 机一般不需要指定自己的套接字地址(IP 地址和端口号),系统会自动从1024 至5000的端口号范围内为它选择一个未用的端口号,然后以这个端口号和本机 的 IP 地址填充这个套接字地址。
客户机调用函数 connect 来主动建立连接。这个函数将启动 TCP 协议的3次 握手过程。在建立连接之后或发生错误时函数返回。连接过程可能出现的错误情 况有:
(2) 如果远程 TCP 协议返回一个 RST 数据段,函数立即以错误返回,错 误类型为 ECONNREFUSED。当远程机器在 SYN 数据段指定的目的端口号处
没有服务进程在等待连接时,远程机器的 TCP 协议将发送一个 RST 数据段,向 客户机报告这个错误。客户机的 TCP 协议在接收到 RST 数据段后不再继续发送 SYN 数据段,函数立即以错误返回。
(3) int bcmp(const void * s1,const void * s2,int n):比较参数 s1指 定的内存区域和参数 s2指定的内存区域的前 n 个字节内容,如果相同则返回0, 否则返回非0。
注:以上函数的原型定义在 strings.h 中。 以 mem 开头的函数有: (1) void * memset(void * s,int c,size_t n):将参数 s 指定的内存区 域的前 n 个字节设置为参数 c 的内容。 (2) void * memcpy(void * dest,const void * src,size_t n):功能同 bcopy (),区别:函数 bcopy()能处理参数 src 和参数 dest 所指定的区域有重叠的 情况,memcpy()则不能。 (4) int memcmp(const void * s1,const void * s2,size_t n):比较参 数 s1和参数 s2指定区域的前 n 个字节内容,如果相同则返回0,否则返回非0。 注:以上函数的原型定义在 string.h 中。 9、 基本套接字函数 (1) socket() #include<sys/types.h> #include<sys/socket.h>

Linux的SOCKET编程详解

Linux的SOCKET编程详解

Linux的SOCKET编程详解1. 网络中进程之间如何通信进程通信的概念最初来源于单机系统。

由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如UNIX BSD有:管道(pipe)、命名管道(named pipe)软中断信号(signal)UNIX system V有:消息(message)、共享存储区(shared memory)和信号量(semaphore)等.他们都仅限于用在本机进程之间通信。

网间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。

为此,首先要解决的是网间进程标识问题。

同一主机上,不同进程可用进程号(process ID)唯一标识。

但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。

例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程”这句话就没有意义了。

其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。

因此,网间进程通信还要解决多重协议的识别问题。

其实TCP/IP协议族已经帮我们解决了这个问题,网络层的―ip地址‖可以唯一标识网络中的主机,而传输层的―协议+端口‖可以唯一标识主机中的应用程序(进程)。

这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。

就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说―一切皆s ocket‖。

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

Linux网络编程socket错误码分析

Linux网络编程socket错误码分析

Linux网络编程socket错误分析socket错误码:EINTR:4阻塞的操作被取消阻塞的调用打断。

如设置了发送接收超时,就会遇到这种错误。

只能针对阻塞模式的socket。

读,写阻塞的socket时,-1返回,错误号为INTR。

另外,如果出现EINTR即errno为4,错误描述Interrupted system call,操作也应该继续。

如果recv 的返回值为0,那表明连接已经断开,接收操作也应该结束。

ETIMEOUT:1101、操作超时。

一般设置了发送接收超时,遇到网络繁忙的情况,就会遇到这种错误。

2、服务器做了读数据做了超时限制,读时发生了超时。

3、错误被描述为“connect time out”,即“连接超时”,这种情况一般发生在服务器主机崩溃。

此时客户TCP 将在一定时间内(依具体实现)持续重发数据分节,试图从服务TCP 获得一个ACK 分节。

当最终放弃尝试后(此时服务器未重新启动),内核将会向客户进程返回ETIMEDOUT 错误。

如果某个中间路由器判定该服务器主机已经不可达,则一般会响应“destination unreachable”-“目的地不可达”的ICMP消息,相应的客户进程返回的错误是EHOSTUNREACH 或ENETUNREACH。

当服务器重新启动后,由于TCP 状态丢失,之前所有的连接信息也不存在了,此时对于客户端发来请求将回应RST。

如果客户进程对检测服务器主机是否崩溃很有必要,要求即使客户进程不主动发送数据也能检测出来,那么需要使用其它技术,如配置SO_KEEPALIVE Socket 选项,或实现某些心跳函数。

EAGAIN:1、Send返回值小于要发送的数据数目,会返回EAGAIN和EINTR。

2、recv 返回值小于请求的长度时说明缓冲区已经没有可读数据,但再读不一定会触发EAGAIN,有可能返回0表示TCP连接已被关闭。

3、当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,可以做延时后再重试.4、在Linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno 代码为11(EAGAIN),表明在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。

linux c语言 判断端口是否已经关闭的方法

linux c语言 判断端口是否已经关闭的方法

在Linux下,可以使用C语言中的socket编程来判断一个端口是否已经关闭。

以下是一个简单的示例代码:c复制代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>int main(int argc, char *argv[]) {int sockfd;struct sockaddr_in serv_addr;char buffer[1024];int n;if (argc != 2) {fprintf(stderr, "Usage: %s <port>\n", argv[0]);exit(EXIT_FAILURE);}sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {perror("socket");exit(EXIT_FAILURE);}memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = INADDR_ANY;serv_addr.sin_port = htons(atoi(argv[1])); // 转换为网络字节序if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("bind");exit(EXIT_FAILURE);}if (listen(sockfd, 10) < 0) {perror("listen");exit(EXIT_FAILURE);}while (1) {n = sizeof(serv_addr);int connfd = accept(sockfd, (struct sockaddr *)&serv_addr, &n);if (connfd < 0) {perror("accept");exit(EXIT_FAILURE);}printf("Accept connection from %s:%d\n", inet_ntoa(serv_addr.sin_addr),ntohs(serv_addr.sin_port));close(connfd); // 关闭连接,判断端口是否关闭成功}}这个程序创建了一个TCP服务器,监听指定的端口。

linuxc之解决使用socket函数返回为0的问题

linuxc之解决使用socket函数返回为0的问题

linuxc之解决使用socket函数返回为0的问题
1、问题:
在 linux 平台下写socket,实现简单的tcp通信,服务端第一次调用 socket函数返回 0
2、找原因:
我的代码是这样写的
if ((server_sockfd = socket(AF_INET,SOCK_STREAM, 0) < 0));
特么总是返回0,日了狗
自找方法一:
到网上找为什么socket函数返回0,5分钟过去,没反应
自找方法二:
到网上找linux socket tcp编程
然后得到代码,然后输入终端测试,发现socket返回是3,日了狗,然后再去缩小范围,只执行2行代码,一行实现socket,一行打印结果,依然是3,日了狗,然后再把自己
写的代码也只执行这2行,我插,依然是0,奔溃了,难道socket 还受终端影响,不应该啊,然后果断问旁边做服务端开发的,当然也是搞安卓的,然后我让他看的时候,发现代码写错,那个< 写错位置了,尼玛,3 < 0 否,然后把0给了这个server_sockfd 为0,又因为0 不小于 0,所以代码往下执行
if ((server_sockfd = socket(AF_INET,SOCK_STREAM, 0)) < 0);
3、总结
以后千万不要犯这种傻逼问题,代码要写好。

Linux socket select 函数用法详解

Linux socket select 函数用法详解

linux 的socket函数分为阻塞和非阻塞两种方式,比如accept函数,在阻塞模式下,它会一直等待有客户连接。

而在非阻塞情况下,会立刻返回。

我们一般都希望程序能够运行在非阻塞模式下。

一种方法就是做一个死循环,不断去查询各个socket的状态,但是这样会浪费大量的cpu时间。

解决这个问题的一个方法就是使用select函数。

使用select函数可以以非阻塞的方式和多个socket通信。

当有socket需要处理时,select函数立刻返回,期间并不会占用cpu时间。

例程分析:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define MYPORT 1234 // 侦听端口#define BACKLOG 5 // 最大可连接客户端数量#define BUF_SIZE 200int fd_A[BACKLOG]; // 连接的FD数组int conn_amount; // 当前连接的数量void showclient(){int i;printf("client amount: %d\n", conn_amount);for (i = 0; i < BACKLOG; i++){printf("[%d]:%d ", i, fd_A[i]);}printf("\n\n");}int main(void){int sock_fd, new_fd; // 侦听sock_fd, 新连接new_fdstruct sockaddr_in server_addr; // server address informationstruct sockaddr_in client_addr; // connector's address informationsocklen_t sin_size;int yes = 1;char buf[BUF_SIZE];int ret;int i;//创建侦听Socketif ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("Create listening socket error!");exit(1);}//配置侦听Socket//SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑。

Linux下的CSocket编程--server端的简单示例

Linux下的CSocket编程--server端的简单示例

Linux下的CSocket编程--server端的简单⽰例Linux下的C Socket编程(三)server端的简单⽰例经过前⾯的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的⼀个端⼝上⾯去。

绑定socket到⼀个端⼝上bind()函数可以将socket绑定到⼀个端⼝上,client可以通过向这个端⼝发起请求,端⼝对应的socket便会与client端的socket连接。

#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>int main() {int socket_desc;struct sockaddr_in server;socket_desc = socket(AF_INET, SOCK_STREAM, 0);if (-1 == socket_desc) {perror("cannot create socket");exit(1);}// 监听服务器⾃⾝server.sin_addr.s_addr = INADDR_ANY;server.sin_family = AF_INET;server.sin_port = htons(8888);// 绑定到端⼝if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {perror("cannot bind error");exit(1);}printf("bind success");close(socket_desc);return 0;}对于server.sin_addr.s_addr的更多信息可以参考通过将socket绑定到⼀个确定的端⼝上,我们接下来要做的便是接收这个端⼝下的所有数据。

Linux下C语言的socket函数解析

Linux下C语言的socket函数解析

Linux下C语言的socket函数解析socketsocket()我们使用系统调用socket()来获得文件描述符:#include#includeint socket(int domain,int type,int protocol);第一个参数domain设置为“AF_INET”。

第二个参数是套接口的类型:SOCK_STREAM或SOCK_DGRAM。

第三个参数设置为0。

系统调用socket()只返回一个套接口描述符,如果出错,则返回-1。

bind()一旦你有了一个套接口以后,下一步就是把套接口绑定到本地计算机的某一个端口上。

但如果你只想使用connect()则无此必要。

下面是系统调用bind()的使用方法:#include#includeintbind(int sockfd,struct sockaddr*my_addr,int addrlen);第一个参数sockfd是由socket()调用返回的套接口文件描述符。

第二个参数my_addr是指向数据结构sockaddr的指针。

数据结构sockaddr中包括了关于你的地址、端口和IP地址的信息。

第三个参数addrlen可以设置成sizeof(structsockaddr)。

下面是一个例子:#include#include#include#define MYPORT 3490main(){int sockfd;struct sockaddr_inmy_addr;sockfd=socket(AF_INET,SOCK_STREAM,0);/*do someerror checking!*/my_addr.sin_family=AF_INET;/*hostbyteorder*/my_addr.sin_port=htons(MYPORT);/*short,network byte order*/my_addr.sin_addr.s_addr=inet_addr("132.241.5.10");bzero(&(my_addr.sin_zero),8);/*zero the rest of the struct*//*don't forget your error checking for bind():*/bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));...如果出错,bind()也返回-1。

linux socket 内核原理

linux socket 内核原理

Linux中的Socket是一种用于网络通信的编程接口,它允许进程通过网络进行数据传输。

Socket在Linux内核中的实现涉及到多个组件和原理。

1. 网络协议栈:Linux内核中的网络协议栈负责处理网络通信的各个层次,包括物理层、数据链路层、网络层和传输层。

Socket通过网络协议栈与网络进行交互。

2. 套接字数据结构:在Linux内核中,套接字(Socket)被实现为一种数据结构,用于表示网络连接。

套接字数据结构包含了连接的相关信息,如IP地址、端口号等。

3. 文件描述符:在Linux中,套接字被视为一种文件,因此每个套接字都有一个对应的文件描述符。

通过文件描述符,进程可以对套接字进行读写操作。

4. 网络设备驱动程序:Linux内核中的网络设备驱动程序负责处理网络设备的底层操作,如发送和接收数据包。

套接字通过网络设备驱动程序与网络设备进行通信。

5. 网络协议处理:当进程通过套接字发送或接收数据时,Linux内核会根据套接字的协议类型(如TCP或UDP)进行相应的协议处理。

这包括建立连接、数据分片、错误检测等操作。

6. 系统调用:在用户空间中,进程通过系统调用(如socket、bind、connect等)来创建和操作套接字。

系统调用会触发内核中相应的函数,完成套接字的创建和操作。

总的来说,Linux内核中的Socket实现涉及到网络协议栈、套接字数据结构、文件描述符、网络设备驱动程序、网络协议处理和系统调用等多个组件和原理。

这些组件和原理共同工作,使得进程能够通过套接字进行网络通信。

{"code":0,"msg":"请求出现异常","data":{}}。

基于Linux的Socket网络编程及性能优化

基于Linux的Socket网络编程及性能优化

福建电脑2012年第12期基于Linux的Socket网络编程及性能优化马丽洁(内蒙古电子信息职业技术学院内蒙古呼和浩特010070)【摘要】:本文主要从Socket的建立、配置、连接、数据传输和结束通信五个方面阐述了基于Linux的Socket网络编程的方法和步骤,最后又从最小化报文传输延迟、最小化系统调用负载、为Bandwidth Delay Product调节tcp窗口、动态优化GNU/linux TCP/IP协议栈四个方面进行性能优化,以使应用程序高效、稳定。

【关键词】:Linux,Socket,网络编程,性能优化Socket的英文原义是“孔”或“插座”,通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。

在Internet上的主机一般运行了多个服务软件,同时提供几种服务。

每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

Socket正如其英文原意那样,象一个多孔插座。

一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。

客户软件将插头插到不同编号的插座,就可以得到不同的服务。

socket也是一种文件描述符。

1.Socket编程1.1Socket的建立为了建立Socket,程式能够调用Socket函数,该函数返回一个类似于文档描述符的句柄。

Socket描述符是个指向内部数据结构的指针,他指向描述符表入口。

调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。

Socket执行体为您管理描述符表。

两个网络程式之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。

Socket数据结构中包含这五种信息。

1.2Socket的配置通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。

LinuxCSocket编程发送结构体、文件详解及实例

LinuxCSocket编程发送结构体、文件详解及实例

LinuxCSocket编程发送结构体、⽂件详解及实例利⽤Socket发送⽂件、结构体、数字等,是在Socket编程中经常需要⽤到的。

由于Socket只能发送字符串,所以可以使⽤发送字符串的⽅式发送⽂件、结构体、数字等等。

本⽂:1.memcpy Copy block of memory。

内存块拷贝函数,该函数是标准库函数,可以进⾏⼆进制拷贝数据。

函数原型: void * memcpy ( void * destination, const void * source, size_t num ); 函数说明:从source指向的地址开始拷贝num个字节到以destination开始的地址。

其中destination与source指向的数据类型⽆关。

2.Socket传输 使⽤memcpy将⽂件、结构体、数字等,可以转换为char数组,之后进⾏传输,接收⽅在使⽤memcpy将char数组转换为相应的数据。

下⾯的程序使⽤Socket传输结构体数据,由客户端传输给服务器端。

传输的结构体为:typedef struct{int ab;int num[1000000];}Node;服务器代码:1 #include<netinet/in.h>2 #include<sys/types.h>3 #include<sys/socket.h>4 #include<stdio.h>5 #include<stdlib.h>6 #include<string.h>78#define HELLO_WORLD_SERVER_PORT 66669#define LENGTH_OF_LISTEN_QUEUE 2010#define BUFFER_SIZE 10241112 typedef struct13 {14int ab;15int num[1000000];16 }Node;1718int main(int argc, char **argv)19 {20// set socket's address information21struct sockaddr_in server_addr;22 bzero(&server_addr, sizeof(server_addr));23 server_addr.sin_family = AF_INET;24 server_addr.sin_addr.s_addr = htons(INADDR_ANY);25 server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);2627// create a stream socket28int server_socket = socket(PF_INET, SOCK_STREAM, 0);29if (server_socket < 0)30 {31 printf("Create Socket Failed!\n");32 exit(1);33 }3435//bind36if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))37 {38 printf("Server Bind Port: %d Failed!\n", HELLO_WORLD_SERVER_PORT);39 exit(1);40 }4142// listen43if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE))45 printf("Server Listen Failed!\n");46 exit(1);47 }4849while(1)50 {51struct sockaddr_in client_addr;52 socklen_t length = sizeof(client_addr);5354int new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);55if (new_server_socket < 0)56 {57 printf("Server Accept Failed!\n");58break;59 }6061 Node *myNode=(Node*)malloc(sizeof(Node));6263int needRecv=sizeof(Node);64char *buffer=(char*)malloc(needRecv);65int pos=0;66int len;67while(pos < needRecv)68 {69 len = recv(new_server_socket, buffer+pos, BUFFER_SIZE, 0);70if (len < 0)71 {72 printf("Server Recieve Data Failed!\n");73break;74 }75 pos+=len;7677 }78 close(new_server_socket);79 memcpy(myNode,buffer,needRecv);80 printf("recv over ab=%d num[0]=%d num[999999]=%d\n",myNode->ab,myNode->num[0],myNode->num[999999]);81 free(buffer);82 free(myNode);83 }84 close(server_socket);8586return0;87 }View Code客户端代码:1 #include <sys/types.h>2 #include <sys/socket.h> // 包含套接字函数库3 #include <stdio.h>4 #include <netinet/in.h> // 包含AF_INET相关结构5 #include <arpa/inet.h> // 包含AF_INET相关操作的函数6 #include <unistd.h>7 #include <string.h>8 #include <stdlib.h>9 #include <fcntl.h>10 #include <sys/shm.h>11 #include <pthread.h>1213#define MYPORT 666614#define BUFFER_SIZE 10241516 typedef struct17 {18int ab;19int num[1000000];20 }Node;2122int main()23 {24///sockfd25int sock_cli = socket(AF_INET,SOCK_STREAM, 0);2627struct sockaddr_in servaddr;28 memset(&servaddr, 0, sizeof(servaddr));29 servaddr.sin_family = AF_INET;30 servaddr.sin_port = htons(MYPORT);31 servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");3233if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)35 perror("connect");36 exit(1);37 }3839 Node *myNode=(Node*)malloc(sizeof(Node));40 myNode->ab=123;41 myNode->num[0]=110;42 myNode->num[999999]=99;4344int needSend=sizeof(Node);45char *buffer=(char*)malloc(needSend);46 memcpy(buffer,myNode,needSend);4748int pos=0;49int len=0;50while(pos < needSend)51 {52 len=send(sock_cli, buffer+pos, BUFFER_SIZE,0); 53if(len <= 0)54 {55 perror("ERRPR");56break;57 }58 pos+=len;59 }60 free(buffer);61 free(myNode);62 close(sock_cli);63 printf("Send over!!!\n");64return0;65 }View Code服务器端执⾏输出:。

Linux下基于TCP的预先派生子进程服务器的Socket编程

Linux下基于TCP的预先派生子进程服务器的Socket编程

No3 .
电 子 设 计 工 程
Elc r n c De in E g n e i g e to i sg n i e r n
2 1 年 2月 01
Fb 2 1 e . 01
Ln x下基 于 T P的预 iu C 先派 生子进程 服务器 的
务 器 能 够及 时 处 理 新 的 客 户连 接 . 响 应 时 间减 小到 并 发 服 务 器 的 三 分之 一 , 到 了 对服 务 器性 能优 化 的 目的 。 且 达
关 键 词 : o k t T P 预 先 派 生 子 进 程 :多进 程 S ce: C : 中图 分 类 号 : P 9 . T 3 30 9 文献标识码 : A 文 章 编 号 :1 7 — 2 6 2 1 ) 3 0 4 — 4 6 4 6 3 (0 10 — 13 0
sre n r- r igs re. in n ev rpo rmsrno C i iu ep ciey T ersl s o dta nte ev ra dp ef kn e r Cl t ds re rga a n P Sw t Ln xrs e t l. h e u ̄ h we h ti h o v e a h v
tesre' p r r n e h e r e o ma c . v s f Ke r s o k t C y wo d :S c e ;T P;p eo k n ;mu t p o e s r fr i g l — r c s i
Sce o k t编 程
和 家强 .刘彦 隆
( 原 理 工 大 学 信 息 工 程 学 院 ,山 西 太 原 0 0 2 ) 太 30 4 摘 要 : 述 了客 户I . 器 模 型 以及 常 见 的服 务 器 类 型— — 基 于 T P的 并 发 服 务 器 。在 一 个基 于 T P 回射 服 务 器 描 J务 l  ̄ C C 程 序 的基 础 上 . 合 实 际 We 结 b应 用 中的 多 进 程 服 务 器模 型 , 虑 到 原 有 的 客 户/ . 器 交 互 存 在 的 问 题 , 进 了客 考 J务 l  ̄ 改 户程 序 . 计 了 实现 并 发 功 能 的 客 户 程 序 、 设 并发 服 务 器 以 及 预 先 派 生 子 进 程 服 务 器 。在 装 有 Ln X的 P iU C上 分 别 进 行 客 户程 序 和服 务 器 程 序 的 测 试 。 实验 结 果 表 明 : 与 并 发 客 户 的 T P交 互 中 , 在 C 与并 发 服 务 器相 比 , 先 派 生 子 进 程 服 预

linux创建socket收发链路层报文的c语言代码

linux创建socket收发链路层报文的c语言代码

linux创建socket收发链路层报文的c语言代码引言概述:在Linux操作系统中,使用C语言编写代码可以创建socket并进行收发链路层报文的操作。

本文将详细介绍如何使用C语言编写代码来实现这一功能。

正文内容:1. socket的创建1.1. 引入必要的头文件:在C语言代码中,需要引入一些必要的头文件,如<sys/types.h>、<sys/socket.h>和<netinet/in.h>等,以便使用相关的函数和数据结构。

1.2. 创建socket:使用socket()函数可以创建一个socket,该函数需要指定协议族、套接字类型和协议类型等参数。

常用的协议族有AF_PACKET(链路层协议族)、AF_INET(IPv4协议族)和AF_INET6(IPv6协议族)等。

1.3. 设置socket选项:可以使用setsockopt()函数来设置socket的选项,如设置接收和发送缓冲区的大小等。

2. 绑定socket2.1. 创建一个用于绑定的结构体:使用struct sockaddr_ll结构体来保存链路层地址信息,包括接口索引、协议类型和目标MAC地址等。

2.2. 绑定socket:使用bind()函数将socket与特定的链路层地址绑定,以便接收和发送链路层报文。

3. 发送链路层报文3.1. 构建报文:使用C语言的数据结构和函数来构建链路层报文,包括设置目标MAC地址、源MAC地址、协议类型和数据等。

3.2. 发送报文:使用sendto()函数发送链路层报文,该函数需要指定socket、报文数据和报文长度等参数。

4. 接收链路层报文4.1. 创建一个接收缓冲区:使用malloc()函数动态分配一个足够大的缓冲区来接收链路层报文。

4.2. 接收报文:使用recvfrom()函数接收链路层报文,该函数需要指定socket、接收缓冲区和缓冲区大小等参数。

5. 关闭socket5.1. 关闭socket:使用close()函数关闭已创建的socket,释放相关资源。

linux socket状态 函数 -回复

linux socket状态 函数 -回复

linux socket状态函数-回复Linux socket状态函数是指用于获取和设置socket连接状态信息的特定函数集合。

这些函数非常重要,因为它们允许开发人员监视和控制网络连接的各个方面,从而确保网络应用程序的可靠性和稳定性。

本文将详细介绍Linux socket状态函数的使用和原理,并提供一些常见的实例和应用场景。

一、什么是socket状态函数Socket状态函数是一组用于获取和设置socket连接状态的API函数。

它们允许开发人员查询和修改socket连接的各个方面,包括连接的状态、缓冲区状态、传输层协议状态等。

通过使用这些函数,开发人员能够更好地监控和管理其网络应用程序,以确保其可靠性和稳定性。

在Linux系统中,socket状态函数主要包括以下几个关键函数:1. getsockopt:用于获取socket选项的值,如缓冲区大小、超时值等。

2. setsockopt:用于设置socket选项的值,如缓冲区大小、超时值等。

3. ioctl:用于控制socket的属性和状态,如非阻塞I/O、接收和发送缓冲区大小等。

4. poll/epoll:用于监视和等待多个socket文件描述符的状态变化,以便及时处理网络事件。

二、getsockopt函数详解getsockopt函数用于获取socket选项的值。

它的原型如下:cint getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);其中,sockfd是socket文件描述符,level表示选项所属的协议层,如SOL_SOCKET表示socket级选项,optname表示具体的选项名称,optval是用于存放选项值的缓冲区,optlen表示缓冲区的长度。

3.1)常见使用场景getsockopt函数广泛应用于网络编程中,主要用于获取和查询socket的各个状态和属性。

SOCKET网络编程:Linux下实现聊天室

SOCKET网络编程:Linux下实现聊天室

SOCKET网络编程:Linux下实现聊天室程序介绍:本聊天室程序在Ubuntu下,采用C语言实现,结构为Client/Server结构;服务端程序通过共享存储区存储聊天数据,并发送给每个连接的客户端;服务端程序和客户端程序都是通过父子进程分别负责发送和接收数据的,以避免数据冲撞;需按以下格式调用客户端程序:client.exe 服务端主机IP 端口号(本程序设定为:3490) 用户名(在聊天室中显示的用户名)。

程序截图://--------------------------------服务端----------------------------------------------//--------------------------------客户端1:真水无香--------------------------------------//--------------------------------客户端2:蜡笔小新--------------------------------------程序代码如下://--------------------------------server.c-------------------------------------------------- //包含工程所需的头文件#include<stdio.h>#include<stdlib.h>#include<sys/types.h>//数据类型定义#include<sys/stat.h>#include<netinet/in.h>//定义数据结构sockaddr_in#include<sys/socket.h>//提供socket函数及数据结构#include<string.h>#include<unistd.h>#include<signal.h>#include<sys/ipc.h>#include<errno.h>#include<sys/shm.h>#include<time.h>#define PERM S_IRUSR|S_IWUSR#define MYPORT 3490 //宏定义定义通信端口#define BACKLOG 10 //宏定义,定义服务程序可以连接的最大客户数量#define WELCOME "|----------Welcome to the chat room! ----------|"//宏定义,当客户端连接服务端时,想客户发送此欢迎字符串//转换函数,将int类型转换成char *类型void itoa(int i,char*string){int power,j;j=i;for(power=1;j>=10;j/=10)power*=10;for(;power>0;power/=10){*string++='0'+i/power;i%=power;}*string='\0';}//得到当前系统时间void get_cur_time(char * time_str){time_t timep;struct tm *p_curtime;char *time_tmp;time_tmp=(char *)malloc(2);memset(time_tmp,0,2);memset(time_str,0,20);time(&timep);p_curtime = localtime(&timep);strcat(time_str," (");itoa(p_curtime->tm_hour,time_tmp);strcat(time_str,time_tmp);strcat(time_str,":");itoa(p_curtime->tm_min,time_tmp);strcat(time_str,time_tmp);strcat(time_str,":");itoa(p_curtime->tm_sec,time_tmp);strcat(time_str,time_tmp);strcat(time_str,")");free(time_tmp);}//创建共享存储区key_t shm_create(){key_t shmid;//shmid = shmget(IPC_PRIVATE,1024,PERM);if((shmid = shmget(IPC_PRIVATE,1024,PERM)) == -1){fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno)); exit(1);}return shmid;}//端口绑定函数,创建套接字,并绑定到指定端口int bindPort(unsigned short int port){int sockfd;struct sockaddr_in my_addr;sockfd = socket(AF_INET,SOCK_STREAM,0);//创建基于流套接字my_addr.sin_family = AF_INET;//IPv4协议族my_addr.sin_port = htons(port);//端口转换my_addr.sin_addr.s_addr = INADDR_ANY;bzero(&(my_addr.sin_zero),0);if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr)) == -1){perror("bind");exit(1);}printf("bing success!\n");return sockfd;}int main(int argc, char *argv[]){int sockfd,clientfd,sin_size,recvbytes; //定义监听套接字、客户套接字pid_t pid,ppid; //定义父子线程标记变量char *buf, *r_addr, *w_addr, *temp, *time_str;//="\0"; //定义临时存储区struct sockaddr_in their_addr; //定义地址结构key_t shmid;shmid = shm_create(); //创建共享存储区temp = (char *)malloc(255);time_str=(char *)malloc(20);sockfd = bindPort(MYPORT);//绑定端口while(1){if(listen(sockfd,BACKLOG) == -1)//在指定端口上监听{perror("listen");exit(1);}printf("listening......\n");if((clientfd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size)) == -1)//接收客户端连接{perror("accept");exit(1);}printf("accept from:%d\n",inet_ntoa(their_addr.sin_addr));send(clientfd,WELCOME,strlen(WELCOME),0);//发送问候信息 buf = (char *)malloc(255);ppid = fork();//创建子进程if(ppid == 0){//printf("ppid=0\n");pid = fork(); //创建子进程while(1){if(pid > 0){//父进程用于接收信息memset(buf,0,255);//printf("recv\n");//sleep(1);if((recvbytes = recv(clientfd,buf,255,0)) <= 0) {perror("recv1");close(clientfd);raise(SIGKILL);exit(1);}//write buf's data to share memoryw_addr = shmat(shmid, 0, 0);memset(w_addr, '\0', 1024);strncpy(w_addr, buf, 1024);get_cur_time(time_str);strcat(buf,time_str);printf(" %s\n",buf);}else if(pid == 0){//子进程用于发送信息//scanf("%s",buf);sleep(1);r_addr = shmat(shmid, 0, 0);//printf("---%s\n",r_addr);//printf("cmp:%d\n",strcmp(temp,r_addr));if(strcmp(temp,r_addr) != 0){strcpy(temp,r_addr);get_cur_time(time_str);strcat(r_addr,time_str);//printf("discriptor:%d\n",clientfd);//if(send(clientfd,buf,strlen(buf),0) == -1)if(send(clientfd,r_addr,strlen(r_addr),0) == -1){perror("send");}memset(r_addr, '\0', 1024);strcpy(r_addr,temp);}}elseperror("fork");}}}printf("------------------------------\n");free(buf);close(sockfd);close(clientfd);return 0;}//-----------------------------client.c------------------------------------------------- //包含工程所需的头文件#include<stdio.h>#include<netinet/in.h>//定义数据结构sockaddr_in#include<sys/socket.h>//提供socket函数及数据结构#include<sys/types.h>//数据类型定义#include<string.h>#include<stdlib.h>#include<netdb.h>#include<unistd.h>#include<signal.h>#include<time.h>int main(int argc, char *argv[]){struct sockaddr_in clientaddr;//定义地址结构pid_t pid;int clientfd,sendbytes,recvbytes;//定义客户端套接字struct hostent *host;char *buf,*buf_r;if(argc < 4){printf("usage:\n");printf("%s host port name\n",argv[0]);exit(1);}host = gethostbyname(argv[1]);if((clientfd = socket(AF_INET,SOCK_STREAM,0)) == -1) //创建客户端套接字{perror("socket\n");exit(1);}//绑定客户端套接字clientaddr.sin_family = AF_INET;clientaddr.sin_port = htons((uint16_t)atoi(argv[2]));clientaddr.sin_addr = *((struct in_addr *)host->h_addr);bzero(&(clientaddr.sin_zero),0);if(connect(clientfd,(struct sockaddr *)&clientaddr,sizeof(struct sockaddr)) == -1) //连接服务端{perror("connect\n");exit(1);}buf=(char *)malloc(120);memset(buf,0,120);buf_r=(char *)malloc(100);if( recv(clientfd,buf,100,0) == -1){perror("recv:");exit(1);}printf("\n%s\n",buf);pid = fork();//创建子进程while(1){if(pid > 0){//父进程用于发送信息//get_cur_time(time_str);strcpy(buf,argv[3]);strcat(buf,":");memset(buf_r,0,100);//gets(buf_r);fgets(buf_r,100,stdin);strncat(buf,buf_r,strlen(buf_r)-1);//strcat(buf,time_str);//printf("---%s\n",buf);if((sendbytes = send(clientfd,buf,strlen(buf),0)) == -1) {perror("send\n");exit(1);}}else if(pid == 0){//子进程用于接收信息memset(buf,0,100);if(recv(clientfd,buf,100,0) <= 0){perror("recv:");close(clientfd);raise(SIGSTOP);exit(1);}printf("%s\n",buf);}elseperror("fork");}close(clientfd);return 0;}。

Linux进程间通信方式之socket使用实例

Linux进程间通信方式之socket使用实例

Linux进程间通信⽅式之socket使⽤实例套接字是⼀种通信机制,凭借这种机制,客户/服务器系统的开发⼯作既可以在本地单机上进⾏,也可以跨⽹络进⾏。

套接字的特性有三个属性确定,它们是:域(domain),类型(type),和协议(protocol)。

套接字还⽤地址作为它的名字。

地址的格式随域(⼜被称为协议族,protocol family)的不同⽽不同。

每个协议族⼜可以使⽤⼀个或多个地址族定义地址格式。

1.套接字的域域指定套接字通信中使⽤的⽹络介质。

最常见的套接字域是AF_INET,它是指Internet⽹络,许多Linux局域⽹使⽤的都是该⽹络,当然,因特⽹⾃⾝⽤的也是它。

其底层的协议——⽹际协议(IP)只有⼀个地址族,它使⽤⼀种特定的⽅式来指定⽹络中的计算机,即IP地址。

在计算机系统内部,端⼝通过分配⼀个唯⼀的16位的整数来表⽰,在系统外部,则需要通过IP地址和端⼝号的组合来确定。

2.套接字类型流套接字(在某些⽅⾯类似域标准的输⼊/输出流)提供的是⼀个有序,可靠,双向字节流的连接。

流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP连接实现的。

他们也是AF_UNIX域中常见的套接字类型。

数据包套接字与流套接字相反,由类型SOCK_DGRAM指定的数据包套接字不建⽴和维持⼀个连接。

它对可以发送的数据包的长度有限制。

数据报作为⼀个单独的⽹络消息被传输,它可能会丢失,复制或乱序到达。

数据报套接字实在AF_INET域中通过UDP/IP连接实现,它提供的是⼀种⽆需的不可靠服务。

3.套接字协议只要底层的传输机制允许不⽌⼀个协议来提供要求的套接字类型,我们就可以为套接字选择⼀个特定的协议。

先上⼀个代码服务端://s_unix.c#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#define UNIX_DOMAIN "/tmp/UNIX.domain"int main(void){socklen_t clt_addr_len;int listen_fd;int com_fd;int ret;int i;static char recv_buf[1024];int len;struct sockaddr_un clt_addr;struct sockaddr_un srv_addr;listen_fd=socket(PF_UNIX,SOCK_STREAM,0);if(listen_fd<0){perror("cannot create communication socket");return 1;}//set server addr_paramsrv_addr.sun_family=AF_UNIX;strncpy(srv_addr.sun_path,UNIX_DOMAIN,sizeof(srv_addr.sun_path)-1);unlink(UNIX_DOMAIN);//bind sockfd & addrret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));if(ret==-1){perror("cannot bind server socket");close(listen_fd);unlink(UNIX_DOMAIN);return 1;}//listen sockfdret=listen(listen_fd,1);if(ret==-1){perror("cannot listen the client connect request");close(listen_fd);unlink(UNIX_DOMAIN);return 1;}//have connect request use acceptlen=sizeof(clt_addr);com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);if(com_fd<0){perror("cannot accept client connect request");close(listen_fd);unlink(UNIX_DOMAIN);return 1;}//read and printf sent client infoprintf("/n=====info=====/n");for(i=0;i<4;i++){memset(recv_buf,0,1024);int num=read(com_fd,recv_buf,sizeof(recv_buf));printf("Message from client (%d)) :%s/n",num,recv_buf);}close(com_fd);close(listen_fd);unlink(UNIX_DOMAIN);return 0;}客户端://c_unix.c#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#define UNIX_DOMAIN "/tmp/UNIX.domain"int main(void){int connect_fd;int ret;char snd_buf[1024];int i;static struct sockaddr_un srv_addr;//creat unix socketconnect_fd=socket(PF_UNIX,SOCK_STREAM,0);if(connect_fd<0){perror("cannot create communication socket");return 1;}srv_addr.sun_family=AF_UNIX;strcpy(srv_addr.sun_path,UNIX_DOMAIN);//connect serverret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr)); if(ret==-1){perror("cannot connect to the server");close(connect_fd);return 1;}memset(snd_buf,0,1024);strcpy(snd_buf,"message from client");//send info serverfor(i=0;i<4;i++)write(connect_fd,snd_buf,sizeof(snd_buf));close(connect_fd);return 0;}使⽤套接字除了可以实现⽹络间不同主机间的通信外,还可以实现同⼀主机的不同进程间的通信,且建⽴的通信是双向的通信。

linux socket debug方法

linux socket debug方法

Linux Socket Debug方法是指在Linux系统中,利用Socket API对网络通信进行调试的方法。

通过Socket Debug,开发人员可以在通信过程中捕获和分析数据包,以检查网络连接是否正常、数据传输是否正确。

这对于排查网络故障和优化网络性能非常有帮助。

使用Socket Debug的一般步骤包括:
1.创建一个Socket,使用socket()函数创建一个Socket,指定使用TCP或
UDP协议。

2.绑定Socket,使用bind()函数将Socket与本地IP地址和端口绑定。

3.使Socket进入监听状态,等待客户端连接,使用listen()函数。

4.接受客户端的连接请求,并返回一个新的Socket,使用accept()函数。

5.从客户端接收数据,并进行分析,使用recv()函数。

6.向客户端发送数据,使用send()函数。

7.在数据传输完成后,关闭Socket,使用close()函数。

以上信息仅供参考,可以查阅关于Linux Socket Debug的文献资料以获取更全面准确的信息。

linux 本地socket通信原理

linux 本地socket通信原理

linux 本地socket通信原理Linux本地socket通信原理一、概述在Linux操作系统中,本地socket通信是一种进程间通信的方式,它允许位于同一台计算机上的进程之间进行数据交换。

本地socket 通信是一种高效、可靠的通信机制,被广泛应用于各种场景,如客户端-服务器模型、进程间数据传递等。

二、本地socket的基本概念1. SocketSocket是一种抽象的通信端点,用于进程间的通信。

在本地socket 通信中,每个进程都有一个或多个socket,一个socket可以用于发送和接收数据。

2. 本地socket本地socket是指位于同一台计算机上的两个进程之间的通信机制。

它通过文件系统中的文件来表示,即每个本地socket都与一个文件关联。

三、本地socket通信的流程1. 创建socket本地socket通信的第一步是创建socket。

在Linux中,可以使用socket()系统调用来创建一个本地socket。

创建成功后,系统会返回一个文件描述符,该文件描述符用于后续的通信操作。

2. 绑定socket创建socket后,需要将其绑定到一个特定的文件上。

这个文件可以是已存在的文件,也可以是新创建的文件。

绑定socket的目的是为了让其他进程可以通过该文件找到这个socket。

3. 监听连接如果一个进程希望接收其他进程的连接请求,那么它需要将socket 设置为监听状态。

这可以通过listen()系统调用来实现。

4. 接受连接一旦socket处于监听状态,其他进程就可以通过connect()系统调用来连接到该socket。

被连接的进程可以通过accept()系统调用来接受连接请求,并返回一个新的socket用于后续的通信。

5. 数据交换一旦建立了连接,两个进程就可以通过send()和recv()系统调用来进行数据交换。

其中,send()用于发送数据,recv()用于接收数据。

6. 关闭连接当通信结束后,可以通过close()系统调用来关闭socket。

socket编程函数recvfrom用法

socket编程函数recvfrom用法

Linux‎系统调用-- recv/recvf‎rom 函数详解功能描述:从套接字上‎接收一个消‎息。

对于rec‎v from‎,可同时应用‎于面向连接‎的和无连接‎的套接字。

recv一‎般只用在面‎向连接的套‎接字,几乎等同于‎re cvf‎rom,只要将re‎cvfro‎m的第五个‎参数设置N‎U LL。

如果消息太‎大,无法完整存‎放在所提供‎的缓冲区,根据不同的‎套接字,多余的字节‎会丢弃。

假如套接字‎上没有消息‎可以读取,除了套接字‎已被设置为‎非阻塞模式‎,否则接收调‎用会等待消‎息的到来。

用法:#inclu‎d e <sys/types‎.h>#inclu‎d e <sys/socke‎t.h>ssize‎_t recv(int sock, void *buf, size_‎t len, int flags‎);ssize‎_t recvf‎r om(int sock, void *buf, size_‎t len, int flags‎,struc‎t socka‎d dr *from, sockl‎e n_t *froml‎e n);参数:sock:索引将要从‎其接收数据‎的套接字。

buf:存放消息接‎收后的缓冲‎区。

len:buf所指‎缓冲区的容‎量。

flags‎:是以下一个‎或者多个标‎志的组合体‎,可通过or‎操作连在一‎起MSG_D‎O NTW A‎IT:操作不会被‎阻塞。

MSG_E‎R RQUE‎U E:指示应该从‎套接字的错‎误队列上接‎收错误值,依据不同的‎协议,错误值以某‎种辅佐性消‎息的方式传‎递进来,使用者应该‎提供足够大‎的缓冲区。

导致错误的‎原封包通过‎m sg_i‎o vec作‎为一般的数‎据来传递。

导致错误的‎数据报原目‎标地址作为‎m sg_n‎a me被提‎供。

错误以so‎ck_ex‎tende‎d_err‎结构形态被‎使用,定义如下#defin‎e SO_EE‎_ORIG‎I N_NO‎N E 0#defin‎e SO_EE‎_ORIG‎I N_LO‎C AL 1#defin‎e SO_EE‎_ORIG‎I N_IC‎M P 2#defin‎e SO_EE‎_ORIG‎I N_IC‎M P6 3struc‎t sock_‎e xten‎d ed_e‎r r{u_int‎32_t ee_er‎r no; /* error‎numbe‎r */u_int‎8_t ee_or‎i gin; /* where‎the error‎origi‎n ated‎*/u_int‎8_t ee_ty‎p e; /* type */u_int‎8_t ee_co‎d e; /* code */u_int‎8_t ee_pa‎d;u_int‎32_t ee_in‎f o; /* addit‎i onal‎infor‎m atio‎n */u_int‎32_t ee_da‎t a; /* other‎data *//* More data may follo‎w */};MSG_P‎E EK:指示数据接‎收后,在接收队列‎中保留原数‎据,不将其删除‎,随后的读操‎作还可以接‎收相同的数‎据。

linuxsock_raw原始套接字编程

linuxsock_raw原始套接字编程

linux sock_raw原始套接字编程sock_raw原始套接字编程能够接收到本机网卡上的数据帧或数据包,对与监听网络的流量和分析是很有作用的.一共能够有3种方式创建这种socket1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊明白得一下SOCK_RAW的原理, 比如网卡收到了一个14+20+8+100+4 的udp的以太网数据帧.第一,网卡对该数据帧进行硬过滤(依照网卡的模式不同会有不同的动作,若是设置了promisc混杂模式的话,那么不做任何过滤直接交给下一层输入例程,不然非本机mac或广播mac会被直接抛弃).依照上面的例子,若是成功的话,会进入ip 输入例程.可是在进入ip输入例程之前,系统会检查系统中是不是有通过socket(AF_PACKET, SOCK_RAW, ..)创建的套接字.若是有的话而且协议相符,在那个例子中确实是需要ETH_P_IP或ETH_P_ALL类型.系统就给每一个如此的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.第二,进入了ip输入例程(ip层会对该数据包进行软过滤,确实是检查校验或抛弃非本机ip或广播ip的数据包等,具体要参考源代码),例子中确实是若是成功的话会进入udp输入例程.可是在交给udp输入例程之前,系统会检查系统中是不是有通过socket(AF_INET, SOCK_RAW, ..)创建的套接字.若是有的话而且协议相符,在那个例子中确实是需要IPPROTO_UDP类型.系统就给每一个如此的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.最后,进入udp输入例程 ...ps:若是校验和犯错的话,内核会直接抛弃该数据包的.而可不能拷贝给sock_raw 的套接字,因为校验和都犯错了,数据确信有问题的包括所有信息都没成心义了.进一步分析他们的能力.1. socket(AF_INET, SOCK_RAW, IPPROTO_UDP);能:该套接字能够接收协议类型为(tcp udp icmp等)发往本机的ip数据包,从上面看的确实是20+8+100.不能:不能收到非发往本地ip的数据包(ip软过滤会抛弃这些不是发往本机ip的数据包).不能:不能收到从本机发送出去的数据包.发送的话需要自己组织tcp udp icmp等头部.能够setsockopt来自己包装ip 头部这种套接字用来写个ping程序比较适合2. socket(PF_PACKET, SOCK_RAW, htons(x));那个套接字比较壮大,创建这种套接字能够监听网卡上的所有数据帧.从上面看确实是20+20+8+100.最后一个以太网crc从来都不算进来的,因为内核已经判定过了,对程序来讲没有任何意义了.能: 接收发往本地mac的数据帧能: 接收从本机发送出去的数据帧(第3个参数需要设置为ETH_P_ALL)能: 接收非发往本地mac的数据帧(网卡需要设置为promisc混杂模式)协议类型一共有四个ETH_P_IP 0x800 只接收发往本机mac的ip类型的数据帧ETH_P_ARP 0x806 只同意发往本机mac的arp类型的数据帧ETH_P_ARP 0x8035 只同意发往本机mac的rarp类型的数据帧ETH_P_ALL 0x3 接收发往本机mac的所有类型ip arp rarp的数据帧, 接收从本机发出的所有类型的数据帧.(混杂模式打开的情形下,会接收到非发往本地mac的数据帧)发送的时候需要自己组织整个以太网数据帧.所有相关的地址利用struct sockaddr_ll 而不是struct sockaddr_in(因为协议簇是PF_PACKET不是AF_INET了),比如发送给某个机械,对方的地址需要利用struct sockaddr_ll.这种socket大小通吃,强悍下面是一段相关的代码:perror("iotcl()");return -1;}return 0;}int unset_promisc(char *interface, int fd) {struct ifreq ifr;strcpy(ifr.ifr_name, interface);if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {perror("iotcl()");return -1;}ifr.ifr_flags &= ~IFF_PROMISC;if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {perror("iotcl()");return -1;}return 0;}3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))那个最好不要用,终归我不用...总结利用方式: 1.只想收到发往本机某种协议的ip数据包的话用第一种就足够了2. 更多的详细的内容请利用第二种.包括ETH_P_ALL参数和混杂模式都能够使它的能力不断的增强.ps:很多自己的方式.虚拟机测试环境.有错欢迎指出交流qq:110024218我写的ping#include "arpa/inet.h"#include "signal.h"#include "sys/time.h"extern int errno;int sockfd;struct sockaddr_in addr; //peer addrchar straddr[128]; //peer addr ip(char*)char sendbuf[2048];char recvbuf[2048];int sendnum;int recvnum;int datalen = 30;unsigned short my_cksum(unsigned short *data, int len) {int result = 0;for(int i=0; i<len/2; i++) {result += *data;data++;}while(result >> 16)result = (result&0xffff) + (result>>16);return ~result;}void tv_sub(struct timeval* recvtime, const struct timeval* sendtime) { int sec = recvtime->tv_sec - sendtime->tv_sec;int usec = recvtime->tv_usec - sendtime->tv_usec;if(usec >= 0) {recvtime->tv_sec = sec;recvtime->tv_usec = usec;} else {recvtime->tv_sec = sec-1;recvtime->tv_usec = -usec;}}void send_icmp() {struct icmp* icmp = (struct icmp*)sendbuf;icmp->icmp_type = ICMP_ECHO;icmp->icmp_code = 0;icmp->icmp_cksum = 0;icmp->icmp_id = getpid(); //needn't use htons() call, because peer networking kernel didn't handle this data and won't make different meanings(bigdian litteldian)icmp->icmp_seq = ++sendnum; //needn't use hotns() call too.gettimeofday((struct timeval*)icmp->icmp_data, NULL);int len = 8+datalen;icmp->icmp_cksum = my_cksum((unsigned short*)icmp, len);int retval = sendto(sockfd, sendbuf, len, 0, (struct sockaddr*)&addr, sizeof(addr));if(retval == -1){perror("sendto()");exit(-1);} else {// printf("send icmp request to %s(%d) bytes\n", straddr, len);}}void recv_icmp() {struct timeval *sendtime;struct timeval recvtime;for(;;) {int n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, 0, 0);if(n == -1) {if(errno == EINTR)continue;else {perror("recvfrom()");exit(-1);}} else {gettimeofday(&recvtime, NULL);struct ip *ip = (struct ip*)recvbuf;if(ip->ip_src.s_addr != addr.sin_addr.s_addr) {// printf("ip_src is not : %s\n", straddr);continue;}struct icmp *icmp = (struct icmp*)(recvbuf + ((ip->ip_hl)<<2));if(icmp->icmp_id != getpid()) {// printf("icmp_id is not :%d\n", getpid());continue;}recvnum++;sendtime = (structtimeval*)icmp->icmp_data;tv_sub(&recvtime, sendtime);printf("imcp echo from %s(%dbytes)\tttl=%d\tseq=%d\ttime=%d.%06d s\n", straddr, n, ip->ip_ttl, icmp->icmp_seq, _sec, _usec);}}}void catch_sigalrm(int signum) {send_icmp();alarm(1);}void catch_sigint(int signum) {printf("\nPing statics:send %d packets, recv %d packets, %d%% lost...\n", sendnum, recvnum, (int)((float)(sendnum-recvnum)/sendnum)*100);exit(0);}int main(int argc, char **argv) {if(argc != 2) {printf("please use format: ping hostname\n");exit(-1);}sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);if(sockfd == -1) {perror("socket()");return -1;}/*int sendbufsize = 180;socklen_t sendbufsizelen = sizeof(sendbufsize);if(setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sendbufsize, sendbufsizelen) == -1)perror("setsockopt()");int recvbufsize;socklen_t recvbufsizelen;if(getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recvbufsize, &recvbufsizelen) == -1)perror("getsockopt()");*/memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;int retval = inet_pton(AF_INET, argv[1], &addr.sin_addr);if(retval == -1 || retval == 0) {struct hostent* host = gethostbyname(argv[1]);if(host == NULL) {fprintf(stderr, "gethostbyname(%s):%s\n", argv[1], strerror(errno));exit(-1);}/*if(host->h_name != NULL)printf("hostent.h_name:%s\n", host->h_name);if(host->h_aliases != NULL && *(host->h_aliases) != NULL)printf("hostent.h_aliases:%s\n", *(host->h_aliases));printf("hostent.h_addrtype:%d\n",host->h_addrtype);printf("hostent.h_length:%d\n", host->h_length);*/if(host->h_addr_list != NULL && *(host->h_addr_list) != NULL) {strncpy((char*)&addr.sin_addr,*(host->h_addr_list), 4);inet_ntop(AF_INET, *(host->h_addr_list), straddr, sizeof(straddr));}printf("Ping address:%s(%s)\n\n", host->h_name, straddr);} else {strcpy(straddr, argv[1]);printf("Ping address:%s(%s)\n\n", straddr, straddr);}struct sigaction sa1;memset(&sa1, 0, sizeof(sa1));sa1.sa_handler = catch_sigalrm;sigemptyset(&sa1.sa_mask);sa1.sa_flags = 0;if(sigaction(SIGALRM, &sa1, NULL) == -1)perror("sigaction()");struct sigaction sa2;memset(&sa2, 0, sizeof(sa2));sa2.sa_handler = catch_sigint;sigemptyset(&sa2.sa_mask);sa2.sa_flags = 0;if(sigaction(SIGINT, &sa2, NULL) == -1)perror("sigaction()");。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
recv()函数原型为: int recv(int sockfd,void *buf,int len,unsigned int flags); Sockfd 是接受数据的 socket 描述符;buf 是存放接收数据的缓冲区;len 是缓冲的长 度。Flags 也被置为 0。Recv()返回实际上接收的字节数,当出现错误时,返回-1 并置相应 的 errno 值。 Sendto()和 recvfrom()用于在无连接的数据报 socket 方式下进行数据传输。由于本地 socket 并没有与远端机器建立连接,所以在发送数据时应指明目的地址。 sendto()函数原型为: int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen); 该函数比 send()函数多了两个参数,to 表示目地机的 IP 地址和端口号信息,而 tolen 常常被赋值为 sizeof (struct sockaddr)。Sendto 函数也返回实际发送的数据字节长度或在 出现发送错误时返回-1。 Recvfrom()函数原型为: int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int
Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应 该将 send()的返回值与欲发送的字节数进行比较。当 send()返回值与 len 不匹配时,应该对 这种情况进行处理。 char *msg = "Hello!"; int len, bytes_sent; …… len = strlen(msg); bytes_sent = send(sockfd, msg,len,0); ……
在 Internet 上传输数据时就需要进行转换,否则就会出现数据不一致。 下面是几个字节顺序转换函数:
·htonl():把 32 位值从主机字节序转换成网络字节序 ·htons():把 16 位值从主机字节序转换成网络字节序 ·ntohl():把 32 位值从网络字节序转换成主机字节序 ·ntohs():把 16 位值从网络字节序转换成主机字节序
type 参数指定 socket 的类型: SOCK_STREAM 或 SOCK_DGRAM,Socket 接口还定义 了原始 Socket(SOCK_RAW),允许程序使用低层协议;protocol 通常赋值"0"。 Socket() 调用返回一个整型 socket 描述符,你可以在后面的调用使用它。
用 bind 函数来配置本地信息。 Bind 函数将 socket 与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。Bind 函数原型为:
int bind(int sockfd,struct sockaddr *my_addr, int addrlen); Sockfd 是调用 socket 函数返回的 socket 描述符,my_addr 是一个指向包含有本机 IP 地址及端口号等信息的 sockaddr 类型的指针;addrlen 常被设置为 sizeof(struct sockaddr)。 struct sockaddr 结构类型是用来保存 socket 信息的: struct sockaddr { unsigned short sa_family; /* 地址族, AF_xxx */ char sa_data[14]; /* 14 字节的协议地址 */ }; sa_family 一般为 AF_INET,代表 Interne(t TCP/IP)地址族;sa_data 则包含该 socket 的 IP 地址和端口号。 另外还有一种结构类型: struct sockaddr_in { short int sin_family; /* 地址族 */ unsigned short int sin_port; /* 端口号 */ struct in_addr sin_addr; /* IP 地址 */ unsigned char sin_zero[8]; /* 填充 0 以保持与 struct sockaddr 同样大小 */ }; 这个结构更方便使用。sin_zero 用来将 sockaddr_in 结构填充到与 struct sockaddr 同 样的长度,可以用 bzero()或 memset()函数将其置为零。指向 sockaddr_in 的指针和指向 sockaddr 的指针可以相互转换,这意味着如果一个函数所需参数类型是 sockaddr 时,你可 以在函数调用的时候将一个指向 sockaddr_in 的指针转换为指向 sockaddr 的指针;或者相 反。 使用 bind 函数时,可以用下面的赋值实现自动获得本机 IP 地址和随机获取一个没有被 占用的端口号: my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机 IP 地址 */ 通过将 my_addr.sin_port 置为 0,函数会自动为你选择一个未占用的端口来使用。同样,通 过将 my_addr.sin_addr.s_addr 置为 INADDR_ANY,系统会自动填入本机 IP 地址。 注意在使用 bind 函数是需要将 sin_port 和 sin_addr 转换成为网络字节优先顺序;而 sin_addr 则不需要转换。 计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet 上数据 以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,
Bind()函数在成功被调用时返回 0;出现错误时返回"-1"并将 errno 置为相应的错误号。 需要注意的是,在调用 bind 函数时一般不要将端口号置为小于 1024 的值,因为 1 到 1024 是保留端口号,你可以选择大于 1024 中的任何一个没有被占用的端口号。
连接建立 面向连接的客户程序使用 Connect 函数来配置 socket 并与远端服务器建立一个 TCP
int listen(int sockfd, int backlog); Sockfd 是 Socket 系统调用返回的 socket 描述符;backlog 指定在请求队列中允许的最大 请求数,进入的连接请求将在队列中等待 accept()它们(参考下文)。Backlog 对队列中等 待 服务的请求的数目进行了限制,大多数系统缺省值为 20。如果一个服务请求到来时,输 入队列已满,该 socket 将拒绝连接请求,客户将收到一个出错信息。 当出现错误时 listen 函数返回-1,并置相应的 errno 错误码。
Linux 下 Socket 编程
网络的 Socket 数据传输是一种特殊的 I/O,Socket 也是一种文件描述符。Socket 也 具有一个类似于打开文件的函数调用 Socket(),该函数返回一个整型的 Socket 描述符,随 后的连接建立、数据传输等操作都是通过该 Socket 实现的。
Connect 函数启动和远端主机的直接连接。只有面向连接的客户程序使用 socket 时才 需要将此 socket 与远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从 不启动一个连接,它只是被动的在协议端口监听客户的请求。
Listen 函数使 socket 处于被动的监听模式,并为该 socket 建立一个输入数据队列, 将到达的服务请求保存在此队列中,直到程序处理它们。
什么是 Socket Socket 接口是 TCP/IP 网络的 API,Socket 接口定义了许多函数或例程,程序员可以
用它们来开发 TCP/IP 网络上的应用程序。要学 Internet 上的 TCP/IP 网络编程,必须理解 Socket 接口。
Socket 接口设计者最先是将接口放在 Unix 操作系统里面的。如果了解 Unix 系统的 输入和输出的话,就很容易了解 Socket 了。网络的 Socket 数据传输是一种特殊的 I/O, Socket 也是一种文件描述符。Socket 也具有一个类似于打开文件的函数调用 Socket(),该 函数返 回一个整型的 Socket 描述符,随后的连接建立、数据传输等操作都是通过该 Socket 实现的。常用的 Socket 类型有两种:流式 Socket (SOCK_STREAM)和数据报式 Socket (SOCK_DGRAM)。流式是一种面向连接的 Socket,针对于面向连接的 TCP 服务应用; 数据 报式 Socket 是一种无连接的 Socket,对应于无连接的 UDP 服务应用。
Socket 建立 为了建立返回一个类似于文件描述符的
句柄。socket 函数原型为: int socket(int domain, int type, int protocol); domain 指明所使用的协议族,通常为 PF_INET,表示互联网协议族(TCP/IP 协议族);
accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用 accept 函数,然后睡眠并等待客户的连接请求。
int accept(int sockfd, void *addr, int *addrlen); sockfd 是被监听的 socket 描述符,addr 通常是一个指向 sockaddr_in 变量的指针, 该变量用来存放提出连接请求服务的主机的信息(某 台主机从某个端口发出该请求); addrten 通常为一个指向值为 sizeof(struct sockaddr_in)的整型指针变量。出现错误时
数据传输 Send()和 recv()这两个函数用于面向连接的 socket 上进行数据传输。 Send()函数原型为: int send(int sockfd, const void *msg, int len, int flags);
相关文档
最新文档