博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux下socket编程
阅读量:6841 次
发布时间:2019-06-26

本文共 5897 字,大约阅读时间需要 19 分钟。

hot3.png

  • Socket

   soket接口是TCP/IP网络的API。网络的socket数据传输是一种特别的I/O,socket也是一种文档描述符。利用socket()函数打开,返回一个整型的socket描述符,然后建立连接,数据传输等等。常用的socket类型有:流式socket(SOCK_STREAM)、数据报socket(SOCK_DGRAM). 其中流式socket是采用面向连接的TCP服务,而数据报socket则是无连接的UDP服务

  • Socket建立

    调用: int socket(int domain, int type, int prococol)来创建socket

    domain:指明所使用的协议族,常用PF_INET, 表示互联网协议族(TCP/IP)

       说明:

                        在绑定本地地址或连接远程地址时需要初始化sockaddr_in结构,其中指定address family时一般设置为AF_INET,即使用IP。

                        相关头文件中的定义:AF = Address Family

                    PF = Protocol Family
                    AF_INET = PF_INET

            因此,一般规范的用法是在socket中用PF_INET指定协议族,在设置address中时,使用AF_NET,当然两者是一样的。

    type:指定socket的类型,分为:SOCK_STREAM(TCP)、SOCK_DGRAM(UDP),SOCK_RAW(原始socket,允许socket调用底层协议)

    protocol:通常赋值为0

    socket描述符是一个指向内部数据结构的指针,执行描述符表的入口

    两个网络程式之间的一个网络连接包括:通信协议、本地协议地址、本地主机端口、远端主机地址、远端协议端口

    

  • socket配置

    面向连接的socket客户端通过调用connet函数在socket数据接口中保存本地和远端信息,无连接socket的客户端和服务端联通面向连接socket的服务端通过调用bind函数来配置本地信息

    1. int bind(int sockefd, struct sockaddr *my_addr, int addrlen);

    

struct sockaddr{        unsigned short sa_family; // 地址族, AF_INET...    char sa_data[14]; // 14字节的协议地址}说明,其中sa_family一般为AF_INET,代表tcp/ip协议族,sa_data则包含该socket的IP地址和端口号struct sockaddr_in{    short int sin_family; // 地址族    unsigned short int sin_port; // 端口号    struct in_addr sin_addr; // ip地址    unsigned char sin_zero[8]; // 填充0以保证和struct sockaddr同样大小}第二个结构体更常用,用bzero()或memset()函数将其该结构体置为零指向sockaddr_in的指针和指向sockaddr的指针能够相互转换my_addr.sin_port = 0; // 表示随机获取一个没有被占用的端口号my_addr.sin_addr.s_addr = INADDR_ANY; // 自动填入本机IP地址my_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 客户端的填充IP方式

    bind函数需要将sin_port和sin_addr转换成为网络字节有限顺序,而sin_addr则无需转换

    internet上数据以高位优先 顺序传输,故需要实现进行转换

htonl(); 把32位值从主机字节序转换为网络字节序htons(); 把16位值从主机字节序转换为网络字节序ntohl(); 把32位值从网络字节序转换为主机字节序ntohs(); 把16位值从网络字节序转换为主机字节序

    bind函数在成功调用后,返回0,出错返回-1并将errno设置为响应的错误号

  • 建立连接

    面向连接的客户程式使用connet函数来配置socket并和远端服务器建立一个TCP连接

    int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

    sockfd是socket函数返回的socket描述符

    serv_addr: 包含远端主机ip地址和端口号的指针   

    addrlen: 为远端地址结构的长度, sizeof(sockaddr)

    connect函数只用于面向连接的客户端程式,无连接和面向连接的服务器不需要,成功则返回0,失败返回-1

    

    listen函数使socket处于被动的监听模式,并为该socket模式建立一个输入数据队列,将到达的服务请求保存在队列中

    int listen(int sockfd,int backlog)

    sockfd:为socket描述符

    backlog: 自定在请求队列中允许的最大请求数

    

    accept函数让服务器接受客户的连接请求,在建立好输入队列后,服务器调用accept函数,然后睡眠并等待客户端的连接唤醒

    int accept(int sockfd, void *addr, int *addrlen)

    sockfd:是被监听的socked秒速富

    addr:通常是个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机信息;

    addrlen:通常是一个指向值为sizeof(struct sockaddr_in)的整型指针变量

    accept函数监控的 socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍能够继续在以前的 socket上监听,同时能够在新的socket描述符上进行数据传输操作

  • 数据传输

   send和recv用于面向连接的socket上进行数据传输     

    int send(int sockfd, const void *msg, int len, int flags)

    sockfd: 是想用来传输数据的socket描述符

    msg: 指向要发送数据的指针

    len:以直接为单位的数据长度

    flags:一般设置为0

    返回实际上发送出的字节数,可能会少于希望发送的数据;在程序中应该将send发送的数据和len进行比较,若不匹配时,应该进行处理

char *msg = "hello world";int len = strlen(msg), bytes_sent;bytes_sent = send(sockfd, msg, len, 0);if(bytes_sent != len){    ....}

    int recv(int sockfd, void *buf, int len, unsigned int flags);

    sockfd:接受数据的socket描述符

    buf:为存放接受数据的缓冲区

    len:缓冲区的长度

    flags:一般也被设置为0

    返回实际接受的数据字节数

面向无连接的数据socket以sendto()和recvfrom()来进行数据传输

    int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen)

    to表示目地机的IP地址和端口号信息,而tolen常为sizeof(to)

    int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from , int *fromlen);

    from是sockaddr结构的变量,保存源机的IP地址和端口号,fromlen指向sizeof (struct sockaddr)的变量

结束传输

    close(sockfd);

实例代码:

server.c/* * server.c * *  Created on: 2014-8-29 *      Author: wzb */ #include "server.h"#define temp_pathname "temp.d"void server_process(int sockfd){	char buffer[1024];	int data_len = 0;	FILE *f;	if((f = fopen(temp_pathname, "w")) == NULL)	{		fprintf(stderr, "crete temp file %s error\n", temp_pathname);		exit(1);	}		while((data_len = recv(sockfd, buffer, 1024, 0)) >0)	{		if(data_len < 1024)			buffer[data_len] = '\0';		fprintf(f, "%s", buffer);	}	fclose(f);}int main(){	int sockfd;	int clientfd;	uint16_t port = 10033;		struct sockaddr_in server_addr, client_addr;	bzero(&server_addr, sizeof(server_addr));	server_addr.sin_family = AF_INET;	server_addr.sin_addr.s_addr  = htonl(INADDR_ANY);	server_addr.sin_port = htons(port);		if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)	{		fprintf(stderr, "open data stream socket failed!\n");		exit(1);	}		if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)	{		fprintf(stderr, "bind data socket failed!\n");		exit(1);	}		if(listen(sockfd, SOMAXCONN) < 0)	{		fprintf(stderr, "listen data stream failed\n");		exit(1);	}		while(1)	{		socklen_t len = sizeof(client_addr);		clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &len);		if(clientfd < 0)		{			fprintf(stderr, "accept error\n");			continue;		}				int pid = fork();		if(pid == 0)		{			server_process(clientfd);			exit(0);		}		close(clientfd);	}	return 0;	 }

client.c/* * client.c * *  Created on: 2014-8-29 *      Author: wzb */ #include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define filename "file.d"int main(){ int sockfd; struct sockaddr_in server_addr; uint16_t port = 10033; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "socket eerror\n"); exit(1); } bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");; if(connect(sockfd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr))<0) { fprintf(stderr, "connect eerror\n"); return -1; } FILE *f = NULL; if((f = fopen(filename, "r")) == NULL) { fprintf(stderr, "%s file error\n", filename); close(sockfd); exit(1); } char buf[LINE_MAX]; while(fgets(buf, LINE_MAX, f)) { send(sockfd, buf, strlen(buf), 0); } fclose(f); printf("-----------send over------------\n"); close(sockfd); return 0;}

        

转载于:https://my.oschina.net/u/566591/blog/308672

你可能感兴趣的文章