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 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的问题
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函数分为阻塞和非阻塞两种方式,比如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下的socket网络编程在STM-1 IMA数据采集卡中的应用
复 型服务 器 。
由于 U P尽最大努力交付但提供不可靠 的服务 , D 简
单 的 U P算 法 可 以在 本 地 网络 条 件好 的环 境 中 良 D 好工作 ;但 在环境 较 复杂 的 网络 中就 不 能正 常工 作
了 , 须通 过 超 时和 重传 来 实现 可 靠性 。而 T P则 必 C
且效 率更 高 , 并发 技术 中最 常用 的方式 。 2是 一 是 图 种 典 型 的多线程 编程 流程 图 。
主线 程 工作 线程 来自通 常 客 户 应 用 程 序 比服 务 器 应 用 程 序 简单 的 多, 因为 大多数 客户端 不需 要 明显处 理并 发 , 并且 不
需要考 虑其 它异 常 。 而服 务器 端则要 复 杂得多 , 需要 考虑 并发 、 行 效率 、 执 网络 状 况 、 客户 状态 和 服 务器 崩溃等 等诸 多方 面问题 。 因此 , 一个 网络通 讯程 序 的 关 键在 于服 务器应 用程序 的开发 。根据 服务 器模 型 是 否提供 并发 ,可 以将服 务 器大致 分 为重复 型服 务
Qi i . 竺 !
2 ……… 一 o 一 一 l …
…
…
…
…
…
…
…
…
…
。
M
^ Y MN1 I 0 McN F As 觚oUT I 0
向非连接 两种 。如果采 用 T P协议则 是 面 向连 接 的 C 通讯 ,如 果采 用 U P协 议 则是 面 向非 连接 的通讯 。 D
而在 Ln x下开发 高性 能的网络通讯程序 ,是 充 iu 分发挥 Ln x网络特性 的一 个关键 因素 。文章通 iu
过 对 S ce 通 讯 模 型 的 分 析 和 比较 , ok t 阐述 了在 数 据 采 集 系统 中 采 用 S ce 通 讯 技 术 的 必要 性 , okt 并 且 以 S M一 MA数 据 采 集 卡 为例 , 细说 明 了如 T 1 I 详
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、glibc中socket系统调用实现
/* %eax is < 0 if there was an error. */ cmpl $-125, %eax jae SYSCALL_ERROR_LABEL
/* Successful; return the syscall's value. */ L(pseudo_end):
ret ……
代码# define __socket socket 将__socket 定义为 socket,因此 ENTRY (__socket)即为 ENTRY (socket) 在这段汇编代码中,我们在 eax 保存当前系统调用号(这里是 socketcall),查看 SYS_ify 的定义,在 glibc/sysdeps/unix/sysv/linux/i386/sysdep.h 中:
#ifndef _SYS_SOCKETCALL_H #define _SYS_SOCKETCALL_H 1
/* Define unique numbers for the operations permitted on socket. Linux uses a single system call for all these functions. The relevant code file is /usr/include/linux/net.h. We cannot use a enum here because the values are used in assembler code. */
movl $SYS_ify(socketcall), %eax /* System call number in %eax. */
/* Use ## so `socket' is a separate token that might be #define'd. */
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。
用uClinux设计和实现Socket编程
n e e o p e d d t w ̄d e sa d r 咖 o k c mmu ia o n ef c o mb d e y t m,a d TC /P p oo o a l ot a e i r q i d f r e t tn a d n h r o n c t n i tra e fr e e d d s se n P I r tc lfmi s f r s e u r o i y w e
P ( ot C时代 , C Ps P ) — 嵌入式系统 已经广泛 的渗透到科学 研究 、 工程设计 、 军事技术 、 各类产业 和商业文化艺术 、 娱乐业以及人们的 日常生活等方方面面中, 成为引人 瞩 目的热点。 现在 , 网络在人们生活中的应用越来越广
协议地址族 , 它对 I 协议族 的实 P 现机制如图 1 所示。 中 B D套 其 S 接字 ( S okt B DS e)由专 门处 理 c B DS kt S e 的通用套接字管理软 c o 件来处理 ,它 由 IE ce 层 N TS kt o 来支持, 这一层为基于 I P的协议 T P和 U P提供端对 端传输管 C D 理。在 Lnx i 操作系统中 ,okt u S e c 属于文件 系统的一部分 , 网络通 信可 以被看作是对文件 的读取。
l户 程f 用进
B D套接字 S IE N T套接字
网络协议 1 ℃
泛 , 然而然 , 自 在嵌入式系统中使用网络 系统也成为了
一
I络 备I 网设
图1 ix 络 L u网 层 结 次 构
项基本的要求。为适应嵌入式分布处理结构和应用
上网需求 ,嵌入式系统要求配备标准的一种或多种 网 络通信接 口, 需要 T P P协议簇软件支持。 Ca
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网络编程example
/* Print the received string */
close(sock); exit(0); }#include <stdio.h> /* for printf() and fprintf() */ #include <sys/socket.h> /* for socket() and bind() */ #include <arpa/inet.h> /* for sockaddr_in */ #include <stdlib.h> /* for atoi() and exit() */ #include <string.h> /* for memset() */ #include <unistd.h> /* for close() */ void DieWithError(char *errorMessage); /* External error handling function */ int main(int argc, char *argv[]) { int sock; /* Socket */ struct sockaddr_in broadcastAddr; /* Broadcast address */ char *broadcastIP; /* IP broadcast address */ unsigned short broadcastPort; /* Server port */ char *sendString; /* String to broadcast */ int broadcastPermission; /* Socket opt to set permission to broadcast */ unsigned int sendStringLen; /* Length of string to broadcast */ if (argc < 4) { fprintf(stderr,"Usage: exit(1); } /* Test for correct number of parameters */ %s <IP Address> <Port> <Send String>\n", argv[0]);
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操作系统中,使用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,释放相关资源。
基本套接字调用
int connect(int sockfd,struct sockaddr * servaddr,int addrlen)
其中参数servaddr指定远程服务器的套接字地址,包括服务器的IP地址和端口号
3、 和服务器端进行网络通信;
使用recv()和send()
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0 )
{
perror("socket");
exit(1);
}
addrlen1 = sizeof(myaddr);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(10000);
此时新建连接,并创建新的Socket套接字,此时addr为客户端的addr信息。
5、 用返回的套接字和客户端进行通信;
使用recv()和send()
int read(int fd,char * buf,int len)
int write(int fd,char * buf,int len)
read_bytes = read(sockfd, buff, strlen(buff));
puts(buff);
}
close(sockfd);
}
exit(1);
}
if(strcmp(argv[3], "-p") != 0)
{
printf("third argument must be: -p\n");
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使⽤实例套接字是⼀种通信机制,凭借这种机制,客户/服务器系统的开发⼯作既可以在本地单机上进⾏,也可以跨⽹络进⾏。
套接字的特性有三个属性确定,它们是:域(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 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编程的端口问题(Address+already+in+use)
Linux下Socket编程的端口问题( Bind(): Address already in use )转载请注明 原文: /xl_xunzhao/archive/2008/10/23/3130037.aspx最近在开发一个Linux下的聊天软件,每次修改了源代码并再次编译运行时,常遇到下面的地使用错误:Cann't bind server socket !: Address already in use虽然用Ctrl+C强制结束了进程,但错误依然存在,用netstat -an |grep 5120和ps aux |grep 5120都还能看到刚才用Ctrl+C“强制结束”了的进程,端口还是使用中,只好每次用kill结束进程,很是麻烦。
昨天晚上无意间浏览到IBM网站上的一篇题为《 Linux 个隐患》的文章,恍然大悟,今天试了一下,果然解决问题,在此表示套接字编程中的 5感谢,也希望更多的coder看到这篇文章,避免出错。
主要代码为:现在我每次用Ctrl+C强制结束进程后,用netstat和ps都还能看到端口在使用中,但运行程序不会出现“Address already in use”的错误了,实现了端口的重用。
以下是原文中的第三个隐患--地址使用错误地址使用错误(EADDRINUSE)您可以使用 bind API 函数来绑定一个地址(一个接口和一个端口)到一个套接字端点。
可以在服务器设置中使用这个函数,以便限制可能有连接到来的接口。
也可以在客户端设置中使用这个函数,以便限制应当供出去的连接所使用的接口。
bind 最常见的用法是关联端口号和服务器,并使用通配符地址(INADDR_ANY),它允许任何接口为到来的连接所使用。
bind 普遍遭遇的问题是试图绑定一个已经在使用的端口。
该陷阱是也许没有活动的套接字存在,但仍然禁止绑定端口(bind 返回 EADDRINUSE),它由 TCP 套接字状态TIME_WAIT 引起。
11实验十一 Linux环境下的SOCKET通信实验
实验十一 Linux环境下的SOCKET通信实验一、实验目的1、掌握Linux下SOCKET编程的基本方法;2、掌握Linux下的常用SOCKET编程函数。
二、实验内容1、编写服务器程序server和客户端程序client;2、编写一个聊天程序的服务器程序listener和客户端程序talker;3、编写Makefile文件;4、下载并调试上述程序。
三、实验设备1、硬件:PC机;DM2410实验系统;串口线;机对机网线;2、软件:PC机操作系统(WINDOWS2000,REDHAT Linux);Linux下ARM GCC交叉编译环境;实验系统附带文件;四、预备知识1、C语言的基础知识;2、程序调试的基础知识和方法;3、Linux的基本操作;4、掌握Linux下的程序编译与交叉编译过程;5、掌握Linux下基本的应用程序编写方法。
五、基础知识介绍如何在Linux环境下进行Socket编程和其常用函数的用法,客户/服务器也即C/S 模型的编程应注意的事项和常遇问题的解决方法。
1、什么是套接字(Socket)客户与服务器应用程序是通过使用传输协议进行通信的。
当应用程序与协议软件进行交互时,它必须说明一些细节,诸如它是个服务器还是个客户(即它是被动等待还是主动启动通信)等。
进行通信的应用程序还必须说明一些进一步的细节(例如,发送方必须说明数据将传给谁,接收方必须说明接收的数据应从何处获得)。
Socket可以看成在两个程序进行通讯连接中的一个端点,一个程序将一段信息写入Socket中,该Socket将这段信息发送给另一个Socket,使这段信息能传送到本地以外的程序中已经处理。
如图11-1:图11-1 Socket通讯过程我们来分析一下上图,Host A上的程序A将一段信息写入Socket中,Socket的内容被Host A的网络管理软件访问,并将这段信息通过Host A的网络接口卡发送到Host B,Host B 的网络接口卡接收到这段信息后,传送给Host B的网络管理软件,网络管理软件将这段信息保存在Host B的Socket中,然后程序B才能在Socket中阅读这段信息。
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、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、基本socket函数Linux系统是通过提供套接字(socket)来进行网络编程的。
网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符。
socket也有一个类似于打开文件的函数:socket(),调用socket(),该函数返回一个整型的socket的描述符,随后的连接建立、数据传输等操作也都是通过该socket实现。
1、socket函数syntax:int socket(int domain, int type, int protocol);功能说明:调用成功,返回socket文件描述符;失败,返回-1,并设置errno参数说明:domain指明所使用的协议族,通常为PF_INET,表示TCP/IP协议;type参数指定socket的类型,基本上有三种:数据流套接字、数据报套接字、原始套接字protocol通常赋值"0"。
两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。
socket数据结构中包含这五种信息。
2、bind函数syntax:int bind(int sock_fd,struct sockaddr_in *my_addr, int addrlen);功能说明:将套接字和指定的端口相连。
成功返回0,否则,返回-1,并置errno.参数说明:sock_fd是调用socket函数返回值,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;struct sockaddr_in结构类型是用来保存socket信息的:struct sockaddr_in {short int sin_family;unsigned short int sin_port;struct in_addr sin_addr;unsigned char sin_zero[8];};addrlen为sockaddr的长度。
3、connect函数syntax:int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen); 功能说明:客户端发送服务请求。
成功返回0,否则返回-1,并置errno。
参数说明:sock_fd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是结构sockaddr_in的长度。
4、listen函数syntax:int listen(int sock_fd, int backlog);功能说明:等待指定的端口的出现客户端连接。
调用成功返回0,否则,返回-1,并置errno.参数说明:sock_fd 是socket()函数返回值;backlog指定在请求队列中允许的最大请求数5、accecpt函数syntax:int accept(int sock_fd, struct sockadd_in* addr, int addrlen);功能说明:用于接受客户端的服务请求,成功返回新的套接字描述符,失败返回-1,并置errno。
参数说明:sock_fd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,addrlen是结构sockaddr_in的长度。
6、write函数syntax:ssize_t write(int fd,const void *buf,size_t nbytes)功能说明:write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量.在网络程序中,当我们向套接字文件描述符写时有俩种可能:1)write的返回值大于0,表示写了部分或者是全部的数据.2)返回的值小于0,此时出现了错误.需要根据错误类型来处理.如果错误为EINTR表示在写的时候出现了中断错误.如果错误为EPIPE表示网络连接出现了问题.7、read函数syntax:ssize_t read(int fd,void *buf,size_t nbyte)函数说明:read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.如果错误为EINTR说明读是由中断引起的,如果错误是ECONNREST表示网络连接出了问题.8、close函数syntax:int close(sock_fd);说明:当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:函数运行成功返回0,否则返回-1二、socket编程的其他函数说明1、网络字节顺序及其转换函数1)网络字节顺序每一台机器内部对变量的字节存储顺序不同,而网络传输的数据是一定要统一顺序的。
所以对内部字节表示顺序与网络字节顺序不同的机器,一定要对数据进行转换,从程序的可移植性要求来讲,就算本机的内部字节表示顺序与网络字节顺序相同也应该在传输数据以前先调用数据转换函数,以便程序移植到其它机器上后能正确执行。
真正转换还是不转换是由系统函数自己来决定的。
2)有关的转换函数* unsigned short int htons(unsigned short int hostshort):主机字节顺序转换成网络字节顺序,对无符号短型进行操作4bytes* unsigned long int htonl(unsigned long int hostlong):主机字节顺序转换成网络字节顺序,对无符号长型进行操作8bytes* unsigned short int ntohs(unsigned short int netshort):网络字节顺序转换成主机字节顺序,对无符号短型进行操作4bytes* unsigned long int ntohl(unsigned long int netlong):网络字节顺序转换成主机字节顺序,对无符号长型进行操作8bytes注:以上函数原型定义在netinet/in.h里2、IP地址转换有三个函数将数字点形式表示的字符串IP地址与32位网络字节顺序的二进制形式的IP地址进行转换(1) unsigned long int inet_addr(const char * cp):该函数把一个用数字和点表示的IP地址的字符串转换成一个无符号长整型,如:struct sockaddr_in inaina.sin_addr.s_addr=inet_addr("202.206.17.101")该函数成功时:返回转换结果;失败时返回常量INADDR_NONE,该常量=-1,二进制的无符号整数-1相当于255.255.255.255,这是一个广播地址,所以在程序中调用iner_addr()时,一定要人为地对调用失败进行处理。
由于该函数不能处理广播地址,所以在程序中应该使用函数inet_aton()。
(2)int inet_aton(const char * cp,struct in_addr * inp):此函数将字符串形式的IP地址转换成二进制形式的IP地址;成功时返回1,否则返回0,转换后的IP地址存储在参数inp中。
(3) char * inet_ntoa(struct in-addr in):将32位二进制形式的IP地址转换为数字点形式的IP地址,结果在函数返回值中返回,返回的是一个指向字符串的指针。
3、字节处理函数Socket地址是多字节数据,不是以空字符结尾的,这和C语言中的字符串是不同的。
Linux提供了两组函数来处理多字节数据,一组以b(byte)开头,是和BSD系统兼容的函数,另一组以mem(内存)开头,是ANSI C提供的函数。
以b开头的函数有:(1) void bzero(void * s,int n):将参数s指定的内存的前n个字节设置为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int n):从参数src指定的内存区域拷贝指定数目的字节内容到参数dest指定的内存区域。
(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中。
二、程序说明本使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端;客户端在接受到数据后打印出来,然后关闭。
1、client.c#include <stdlib.h>#include <sys/types.h>#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>int main(){int cfd;int recbytes;int sin_size;char buffer[1024]={0};struct sockaddr_in s_add,c_add;unsigned short portnum=0x8888;printf("Hello,welcome to client !\r\n");cfd = socket(AF_INET, SOCK_STREAM, 0);if(-1 == cfd){printf("socket fail ! \r\n");return -1;}printf("socket ok !\r\n");bzero(&s_add,sizeof(struct sockaddr_in));s_add.sin_family=AF_INET;s_add.sin_addr.s_addr= inet_addr("192.168.1.2");s_add.sin_port=htons(portnum);printf("s_addr= %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr))){printf("connect fail !\r\n");return -1;}printf("connect ok !\r\n");if(-1 == (recbytes = read(cfd,buffer,1024))){printf("read data fail !\r\n");return -1;}printf("read ok\r\nREC:\r\n");buffer[recbytes]='\0';printf("%s\r\n",buffer);getchar();close(cfd);return 0;}2、server.c#include <stdlib.h>#include <sys/types.h>#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>int main(){int sfp,nfp;struct sockaddr_in s_add,c_add;int sin_size;unsigned short portnum=0x8888;printf("Hello,welcome to my server !\r\n");sfp = socket(AF_INET, SOCK_STREAM, 0);if(-1 == sfp){printf("socket fail ! \r\n");return -1;}printf("socket ok !\r\n");bzero(&s_add,sizeof(struct sockaddr_in));s_add.sin_family=AF_INET;s_add.sin_addr.s_addr=htonl(INADDR_ANY);s_add.sin_port=htons(portnum);if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr))) {printf("bind fail !\r\n");return -1;}printf("bind ok !\r\n");if(-1 == listen(sfp,5)){printf("listen fail !\r\n");return -1;}printf("listen ok\r\n");while(1){sin_size = sizeof(struct sockaddr_in);nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);if(-1 == nfp){printf("accept fail !\r\n");return -1;}printf("accept ok!\r\nServer start get connectfrom %#x : %#x\r\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port ));if(-1 == write(nfp,"hello,welcome to my server \r\n",32)){printf("write fail!\r\n");return -1;}printf("write ok!\r\n");close(nfp);}close(sfp);return 0;}在cygwin下,使用gcc命令编译如下:gcc -o server server.cgcc -o client client.c然后运行程序:./server./clientserver执行效果如下:Hello,welcome to my server !socket ok !bind ok !listen okaccept ok!Server start get connect from 0xc0a80102 : 0xc927write ok!client执行效果如下:Hello,welcome to client !socket ok !s_addr = 0x201a8c0 ,port : 0x8888connect ok !read okREC:hello,welcome to my server什么是SocketSocket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。