您的位置:首页 > 运维架构 > Linux

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地址,网络字节顺序
}


3、字节排序函数
主机和网络的字节顺序是不同的,有大端模式和小段模式之分,通过下面的函数可以进行调整。
#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作用相同,不过返回方式不同,直接通过返回值的方式返回结果


TCP套接字函数
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