Linux socket 初步
2015-04-09 16:29
1676 查看
钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>
最近为了毕设接触了一点Linux socket ,考虑到自己的记性是个大问题,于是写一篇小博文,纯当笔记。基本数据结构及常用函数
开始Linux socket编程之前,需要先来了解一些基本的函数和结构体定义
1、通用套接口地址数据结构
<sys/socket.h> struct sockaddr { uint8_t sa_len; sa_family sa_family; char sa_data[14] }
2、IPv4套接口地址数据结构
<netinet/in.h> struct socketaddr_in { uint8_t sin_len; //长度成员,无需设置 sa_famil_t sin_family; //套接口结构地址表,IPv4为AF_INET in_port_t sin_port; //端口号,16位 struct in_addr sin_addr; unsigned char sin_zero[8]; //未用 }其中,in_addr 是一个结构:
struct in_addr { in_addr_t s_addr; //32位IPv4地址,网络字节顺序 }
主机和网络的字节顺序是不同的,有大端模式和小段模式之分,通过下面的函数可以进行调整。
#include <netinet/in.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);以htonl为例,htonl中h代表host,n代表net,l代表long(htons中,s代表short),
因此htonl表示将本地的long类型数据转化为网络上的long类型,其他几个函数类似,在处理到本机数值到网络数值的时候一定要记住要使用这几个函数!
4、IP地址转化函数
在TCP/IP网络中,我们用到的IP是以“.”隔开的十进制数表示的(在编程中往往就是一个字符串),在套接字的数据结构中用的则是32位的网络字节序的二进制数值,要进行一定的转化才能进行编程。有如下函数
#include<arpa/inet.h> //成功返回1,不成功返回0 int inet_aton(const char * straddr, struct in_addr *addrptr); //将点分十进制的IP地址转换为网络字节序的32位二进制数值,输入的点分十进制数IP //存放在参数straddr中,作为返回结果的二进制数值存放在addrptr中。 //成功返回点分十进制字符串的指正,否则返回NULL char * inet_ntoa(struct in_addr inaddr); //与inet_aton作用相反 //成功返回32位二进制的网络字节序地址,若出错返回INADDR_NONE in_addr_t inet_addr(const char* straddr); //与inet_aton作用相同,不过返回方式不同,直接通过返回值的方式返回结果
1、创建套接字
创建套接口函数系统调用为socket,功能是生成套接口描述符
#include <sys/types.h> #include <sys/socket.h> int socket(int family, int type, int ptotocol);返回:若成功则返回套接字口描述符,否则返回-1
其中,参数family代表协议族,一般有PF_UNIX(UNIX协议族), PF_INET(IPV4协议族),PF_INET6(IPV6协议)等;
type代表通信字节流类型,一般有SOCK_STREAM(TCP方式), SOCK——DGRAM(UDP方式)等
ptotocol一般设为0
2、绑定端口
socket函数创建了一个套接口之后,需要使用bind函数绑定一个对应的IP和端口号
#include<sys/types.h> #include <sys/socket.h> int bind(int sockfd, const struct sockaddr * my_addr, socklen_t addrlen);返回:若成功则返回0,否则返回-1
其中,参数sockfd代表建立的socket编号;
my_addr是一个指向sockaddr结构体的指针;
addrlen代表sockaddr结构体的长度。
3、等待监听函数
listen函数用于服务器监听其他客户端。
#include<sys/socket.h> int listen(int sockfd, int backlog);返回:成功返回0,失败则返回-1
参数中,backlog代表能同时处理的最大连接请求数目。
4、接受连接函数
listen函数并为真正地接受连接,只是设置socket的状态为监听模式,真正接受客户端连接的是accept函数
#include<sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socketlen_t * addrlen);返回:若成功返回一个新的套接口描述符的值,若失败则返回-1
5、请求连接函数
#include<sys/types.h> #include <sys/socket.h> int connet(int sockfd, const struct sockaddr * serv_addr, int addrlen);返回:成功返回0, 否则返回-1
6、数据发送与接受
#include<sys/types.h> #include <sys/socket.h> int send (int sockfd, const void * msg, int len, unsigned int flags); int recv (int sockfd, void * buf, int len, unsigned int flags);flags一般设置为0;
工作流程
实例
server.c
int main() { int sockfd, newsockfd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size, portnumber; char buf[2048]; printf("input portnumber:"); scanf("%d", &portnumber); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket error"); exit(1); } else { printf("socket created successfully\n"); } /*服务器端填充sockaddr结构*/ bzero(&server_addr, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(portnumber); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sockfd, (struct sockaddr *) (&server_addr), sizeof(struct sockaddr)) < 0) { perror("bind failed!"); exit(1); } else { printf("bind successfully\n"); } if (listen(sockfd, 5) < 0) { perror("listen error"); exit(1); } else { printf("listening-----\n"); } while (1) { sin_size = sizeof(struct sockaddr_in); if ((newsockfd = accept(sockfd, (struct sockaddr *) (&client_addr), &sin_size)) < 0) { perror("accept error!"); exit(1); } printf("accept successfully\n"); printf("connect from: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(portnumber)); //printf("input msg:\n"); //scanf("%s", buf); int n; n = recv(newsockfd, buf, sizeof(buf), 0); if (n == -1) { perror("recv failed!\n"); exit(1); } send(newsockfd, "send successfully!\n", 20, 0); buf = '\0'; printf("%s\n", buf); close(newsockfd); } close(sockfd); return 0; }
client.c
int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; struct sockaddr_in servaddr; if( argc != 2){ printf("usage: ./client <ipaddress>\n"); exit(0); } if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(1234); if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ printf("inet_pton error for %s\n",argv[1]); exit(0); } if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: \n"); fgets(sendline, 4096, stdin); if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) { perror("recv error"); exit(1); } buf[rec_len] = '\0'; printf("Received : %s ",buf); close(sockfd); exit(0); }
相关文章推荐
- Linux socket编程学习初步(5)--服务器多线程
- linux socket编程初步(2)
- Linux下的socket编程实践(八) Select的限制和poll(并发的初步知识)
- Linux socket编程学习初步(3)--客户端向服务器请求文件
- Linux下的socket编程实践(八) Select的限制和poll(并发的初步知识)
- Linux-(C)网络编程学习socket(初步)
- Linux 网络程序编程初步 Socket
- Linux socket编程学习初步(4)--服务器端多进程
- linux下TCP socket编程初步(1)
- linux socket 编程
- linux下socket通信,server和client简单例子
- linux socket UDP编程发送广播
- 初步了解linux的系统结构
- Linux Socket 基础实例 (C语言版)-转
- linux 初步试水_安装问题整理_1
- linux下用C/C++和socket实现的驾校约车助手
- 《跟老男孩学Linux运维之shell编程实战》-第一章 shell脚本初步入门
- Linux C Socket编程原理及简单实例
- Linux环境下的Socket编程
- 幽默讲解linux的Socket IO模型