Linux socket 初步

最近为了毕设接触了一点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;


工作流程
Linux socket 初步

实例

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[n] = '\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)