socket编程
Posted sclu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket编程相关的知识,希望对你有一定的参考价值。
一。socket概念
Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。
既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。
二。网络字节序和sockaddr
1.网络字节序
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
#include <arpa/inet.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);
ip转换
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
2.sockaddr数据结构
struct sockaddr_in
__kernel_sa_family_t sin_family; /* Address family */ 地址结构类型
__be16 sin_port; /* Port number */ 端口号
struct in_addr sin_addr; /* Internet address */ IP地址
/* Pad to size of `struct sockaddr‘. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
;
struct sin_addr
uint32 s_addr;
三。socket通信模型
四。socket主要函数
1.socket函数
创建一个套接字,即打开网络通讯端口如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。
2.bind函数
bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号
3.listen函数
listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态
返回值: listen()成功返回0,失败返回-1
4.accept函数
三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度
5.connect函数
客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。
6.客服端服务端套接字通信
服务端
//server.c #include<stdio.h> #include<unistd.h> #include<sys/socket.h> #include<stdlib.h> #include<arpa/inet.h> #include<ctype.h> #include<strings.h> #define SERV_PORT 6666 #define SERV_IP "127.0.0.1" int main() int lfd,cfd; lfd=socket(AF_INET,SOCK_STREAM,0); //创建套接字 ipv4 TCP 方式 socklen_t clie_addr_len; //客户端长度 struct sockaddr_in serv_addr,clie_addr; //定义服务端和客户端sockaddr bzero(&serv_addr,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; //初始化服务端sockaddr 设置ipv4 serv_addr.sin_port=htons(SERV_PORT); //设置 端口号 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); //设置ip INADDR_ANY为本地可用ip bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); //绑定套接字和addr listen(lfd,100); //设置客户端同时连接数 clie_addr_len=sizeof(clie_addr); //获得的客户端sockaddr 长度 cfd=accept(lfd,(struct sockaddr*)&clie_addr,&clie_addr_len); //cfd为与客户端通讯的实际的文件描述符,clie_addr为传出参数,保护客户端地址信息,clie_addr_len为传入传入参数accpet之后会阻塞等待客户端connect printf("client ip:%s,client port:%d\\n",inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,clie_IP,sizeof(clie_IP)),ntohs(clie_addr.sin_port)); char buf[BUFSIZ]; int count,i; while(1) count=read(cfd,buf,sizeof(buf)); //从套接字另一端读数据 for(i=0;i<count;i++) buf[i]=toupper(buf[i]); //将小写字母转换成大写字母 write(cfd,buf,count); //将数据写入 close(cfd); //关闭套接字 close(lfd); //关闭套接字 return 0;
客户端
#include<stdio.h> #include<unistd.h> #include<sys/socket.h> #include<stdlib.h> #include<arpa/inet.h> #include<string.h> #define SERV_IP "127.0.0.1" #define SERV_PORT 6666 int main() int fd; //文件描述符 fd=socket(AF_INET,SOCK_STREAM,0);//创建套接字 struct sockaddr_in serv_addr; //服务器地址 memset(&serv_addr,0,sizeof(serv_addr)); //将serv_addr清0 serv_addr.sin_family=AF_INET; //设置服务器 ipv4 serv_addr.sin_port=htons(SERV_PORT); //端口 inet_pton(fd,SERV_IP,&serv_addr.sin_addr.s_addr); //ip connect(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); //连接服务器 char buf[BUFSIZ]; int count; while(1) fgets(buf,sizeof(buf),stdin); //键盘输入 write(fd,buf,strlen(buf)); //向套接字写数据 count=read(fd,buf,sizeof(buf)); //从服务器读返回的数据 write(STDOUT_FILENO,buf,count); //写到屏幕上 close(fd); return 0;
以上是关于socket编程的主要内容,如果未能解决你的问题,请参考以下文章