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。
- 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网络上的应用程序。