⽹络socket编程(c语⾔)
⼀.socket通信简介
Socket是对TCP/IP协议的封装,Socket本⾝并不是协议,⽽是⼀个调⽤接⼝(API),通过Socket,我们才能使⽤TCP/IP协议,主要利⽤三元组【ip地址,协议,端⼝】。
socket起源于Unix,⽽Unix/Linux基本哲学之⼀就是“⼀切皆⽂件”,都可以⽤“打开open –> 读写write/read –> 关闭close”模式来操作。
Socket()函数返回⼀个整型的Socket描述符,随后的连接建⽴、数据传输等操作都是通过该Socket实现的。Socket是应⽤层与TCP/IP协议族通信的中间软件抽象层。
⼆.⽹络socket客户端和服务器端连接过程如下:
1.1 socket() int socket(int domain,int type, int protocol); 返回值: 成功:返回指向新创建的socket的⽂件描述符,失败:返回-1。
domain:即协议域,⼜称为协议族(family)。常⽤的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采⽤对应的地址,如AF_INET决定了要⽤ipv4地址(32位的)与端⼝号(16位的)的组合、AF_UNIX决定了要⽤⼀个绝对路径名作为地址。
type:创建的套接字的类型,常⽤SOCK_STREAM(流式套接字),SOCK_DGRAM(数据报套接字)
protocol: 传0 表⽰使⽤默认协议。
1.2 bind() int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 返回值:函数执⾏成功返回0,否则返回-1, 并设置错误代码。
sockfd:需要绑定的套接字⽂件描述符。
addr:存⼊⽹络类型,⽹络地址和端⼝号的结构体。
addrlen:addr结构体的长度。
ipv4使⽤的结构体是struct sockaddr_in类型,所以绑定时需要强制类型转换成struct sockaddr类型
struct sockaddr_in
{
sa_family_t sin_family; /* 2 bytes address family, AF_xxx such as AF_INET /
in_port_t sin_port; / 2 bytes port*/
struct in_addr sin_addr; /* 4 bytes IPv4 address*/
unsigned char sin_zero[8]; /* 8 bytes unused padding data, always set be zero */
};
struct sockaddr
{
sa_family_t sa_family; /* 2 bytes address family, AF_xxx /
char sa_data[14]; / 14 bytes of protocol address */
}
在使⽤bind时常⽤的两个函数:htons和htonl,在将⼀个地址绑定到socket的时候,先将主机字节序转换成为⽹络字节序
serv_addr.sin_port = htons(LISTEN_PORT); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
IP地址“127.0.0.1”这是点分⼗进制形式的字符串形式,⽽在结构体struct sockaddr_in 中IP地址是以32位(即4字节整形类型)数据保存的,这时我们可以调⽤ inet_aton() 函数将点分⼗进制字符串转换成 32位整形类型
1.3 listen() int listen(int sockfd,int backlog); 返回值:成功返回0,失败返回-1。 sockfd: socket⽂件描述符 backlog: 排队建⽴3次握⼿队列和刚刚建⽴3次握⼿队列的链接数和
1.4 accept() int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
属性相同的连接套接字,并为这个套接字分配⼀个⽂件描述符,然后以这个描述符返回
返回值:若成功则返回⼀个⾮负整数标识这个连接套接字,发⽣错误时返回-1。
sockfd:⼀个正在⽤于监听功能下的套接字的⽂件描述符。
addr:⽤于储存接受到的客户端的⽹络信息的结构体(参考bind下的使⽤)
addrlen:addr结构体长度
1.5 connect() int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd: 客户端的socket()创建的描述字
addr: 要连接的服务器的socket地址信息,这⾥⾯包含有服务器的IP地址和端⼝等信息
addrlen: socket地址的长度
客户端server.c程序编写
/*********************************************************************************
*      Copyright:  (C) 2021 jiaoer237
*                  All rights reserved.
*
*      Filename:  socket_server.c
*    Description:  This file
*
*        Version:  1.0.0(11/21/2021)
*        Author:  yanp <2405204881@qq>
*      ChangeLog:  1, Release initial version on "11/21/2021 01:59:13 PM"
*
********************************************************************************/
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define PORT 8899
#define BACKLOG 13
int main()
{
int listen_fd,clien_fd=-1;
struct sockaddr_in cli_addr;
socklen_t cliaddr_len;
char buf[1024];
int rv=-1;
listen_fd=socket_server_init(NULL,PORT);/*初始化socket函数*/
while(1)
{
printf("\nstart waiting and accept new \n");
clien_fd=accept(listen_fd,(struct sockaddr*)&cli_addr,&cliaddr_len);/*accept调⽤*/
if(clien_fd<0)
{
printf("accept new client failure:%s\n",strerror(errno));
return-1;
}
printf("accept new client[%s:%d] with fd [%d]\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),clien_fd);
memset(buf,0,sizeof(buf));
rv=read(clien_fd,buf,sizeof(buf));
if(rv<0)
{
printf("read data from socket[%d] failure:%s\n",clien_fd,strerror(errno));
close(clien_fd);
continue;
}
else if(0==rv)
{
printf("read data from socket[%d] failure:%s\n",clien_fd,strerror(errno));
close(clien_fd);
continue;
}
printf("read %d data from server client [%d] and echo it back:'%s'\n",rv,clien_fd,buf);
if(write(clien_fd,buf,rv)<0)
{
printf("write %d bytes data back to client[%d] failure:%s\n",rv,clien_fd,strerror(errno));
close(clien_fd);
}
}
return0;
}
int socket_server_init(char*listen_ip,int listen_port)
{
int listenfd;
struct sockaddr_in servaddr;
if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)/*创建socket描述符*/
{
printf("socket_server to create a TCP socket fd failure:[%s]\n",strerror(errno));
return-1;
}
printf("create a tcp socket fd[%d] success\n",listenfd);
int on=1;
if((setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)/*让端⼝号能够⽴即重复使⽤*/
{
服务器端client.c程序编写        printf ("setsockopt failure:%s",strerror (errno ));
return  -2;
}
memset (&servaddr ,0,sizeof (servaddr ));
servaddr .sin_family =AF_INET ;
servaddr .sin_port =htons (PORT );
if (!listen_ip )/*加⼊传⼊IP 地址则监听指定ip ,否则监听所有ip*/
{
servaddr .sin_addr .s_addr =htonl (INADDR_ANY );
}
else
{
servaddr .sin_addr .s_addr =htonl (listen_port );
}
if (bind (listenfd ,(struct  sockaddr *)&servaddr ,sizeof (servaddr ))<0)/*绑定端⼝号和ip*/
{
printf ("socket[%d] bind on port[%d] for ip address failure:%s\n",listenfd ,listen_port ,strerror (errno ));
return  -2;
}
printf ("socket[%d] bind on port[%d] for ip address success\n"
write的返回值
,listenfd ,listen_port );
listen (listenfd ,BACKLOG );
return  listenfd ;
}
/*********************************************************************************
*      Copyright:  (C) 2021 jiaoer237
*                  All rights reserved.
*
*      Filename:  socket_client.c
*    Description:  This file
*
*        Version:  1.0.0(11/21/2021)
*        Author:  yanp <2405204881@qq>
*      ChangeLog:  1, Release initial version on "11/21/2021 08:49:25 PM"
*
********************************************************************************/
#include  <stdio.h>
#include  <errno.h>
#include  <string.h>
#include  <unistd.h>
#include  <sys/types.h>
#include  <sys/socket.h>
#include  <netinet/in.h>
#include  <arpa/inet.h>
#define  SERVER_PORT 8899
#define  MSG_STR "Hello yanp, Unix Network Program World!"
#define  SERVER_IP "192.168.1.120"
int  main (int  argc ,char  **argv )
{
int  conn_fd = -1;
int  rv = -1;
char  buf [1024];
struct  sockaddr_in serv_addr ;
conn_fd =socket (AF_INET ,SOCK_STREAM ,0);/*socket 创建客户端的描述符*/
if (conn_fd <0)
{
printf ("create client socket failure:%s\n",strerror (errno ));
return  -1;
}
客户端连接服务器之后进⾏读写操作
}
memset (&serv_addr , 0, sizeof (serv_addr ));
serv_addr .sin_family = AF_INET ;
serv_addr .sin_port = htons (SERVER_PORT );
inet_aton (SERVER_IP ,&serv_addr .sin_addr );/*将点分⼗进制转换成32位整型类型*/
if (connect (conn_fd ,(struct  sockaddr *)&serv_addr ,sizeof (serv_addr ))<0)/*连接服务器*/
{
printf ("client[%d] connect to server[%s:%d] failure:%s\n",conn_fd ,SERVER_IP ,SERVER_PORT ,strerror (errno ));        return  -1;
}
if (write (conn_fd ,MSG_STR ,strlen (MSG_STR ))<0)
{
printf ("write data to server[%s,%d] failure:%s\n",SERVER_IP ,SERVER_PORT ,strerror (errno ));
return  -2;
}
memset (buf ,0,sizeof (buf ));
rv =read (conn_fd ,buf ,sizeof (buf ));
if (rv <0)
{
printf ("read data from server failure:%s\n",strerror (errno ));
return  -3;
}
else  if (rv ==0)
{
printf ("client connetc to server get disconnect\n");
return  -4;
}
printf ("read %d bytes from server:'%s'\n",rv ,buf );
return  0;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。