Socket简介

来源:互联网 发布:战地3正在同步云数据 编辑:程序博客网 时间:2024/05/17 23:59

Socket,这是一个老生常谈的话题,我只是梳理一下其相关知识点。
Socket is a port。在Linux中,网络编程是通过Socket接口来完成的。Socket接口是一种特殊的I/O,也是一种文件描述符。
一个Socket 用一个半相关描述: {协议,本地地址,本地端口}。
通过IP可以建立网络中两个设备之间的连接。通过Sockets使用TCP/UDP服务来建立网络中两个应用程序或进程之间的连接。

Socket系统调用包括:socket()、bind()、listen()、accept()、connect()、send()/sendto()、recv()/recvfrom()、read()、write()、close()、shutdown()。

connect()、recv()、send()、read()、write()、都属于阻塞性函数,若资源没有准备好,调用该函数的进程将进入睡眠状态,无法处理I/O多路复用的情况。
fcntl()和select()函数可以用来解决多路复用问题。fcntl()可以实现非阻塞I/O或信号驱动I/O;select()对CPU资源的利用率更高,功能更加强大。

TCP协议中,Socket的服务端和客户端交互:


UDP协议中,Socket的服务端和客户端交互:


一个简单的Linux TCP-Socket编程模型:
请包含头文件:stdio.h、sys/types.h、sys/socket.h、netinet/in.h、arpa/inet.h
server端:tcp_server.c

#include #include #include #include #include #define BUFSIZE 100int main(int argc, char *argv[]){int sockfd;int fd;int len;struct sockaddr_in server_addr; //server网络地址结构体struct sockaddr_in client_addr; //client网络地址结构体int sin_size;char buf[BUFSIZE];memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET; //设置为IP通信server_addr.sin_addr.s_addr = INADDR_ANY; //服务器IP地址---允许连接到所有本地地址上server_addr.sin_port = htons(8000); //server port//get a socket fd TCP类型if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){perror("socket");return -1;}//绑定if( bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0){perror("bind");return -1;}//监听连接请求----监听队列长度为6listen(sockfd, 6);sin_size = sizeof(struct sockaddr_in);//wait for clientif( (fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size)) < 0){perror("accept");return -1;}printf("accept client %s \n", inet_ntoa(client_addr.sin_addr));len = send(fd, "Welcome to my server\n", 21, 0); //连接成功后,发送欢迎消息//接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,sand返回发送的字节数while( (len = recv(fd, buf, BUFSIZE, 0)) > 0){buf[len] = '\0';printf("%s\n", buf);if(send(fd, buf, len, 0) < 0){perror("write");return -1;}}close(fd);close(sockfd);return 0;}client端:tcp_server.c#include #include #include #include #include #define BUFSIZE 100int main(int argc, char *argv[]){int sockfd;int len;struct sockaddr_in client_addr;char buf[BUFSIZE];memset(&client_addr, 0, sizeof(client_addr));//数据初始化--清零client_addr.sin_family = AF_INET; //设置为IP通信client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器IP地址client_addr.sin_port = htons(8000); //服务器端口号//创建客户端套接字if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){perror("socket");return -1;}//将套接字绑定到服务器的网络地址上if(connect(sockfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0){perror("connect");return -1;}printf("connected to server\n");len = recv(sockfd, buf, BUFSIZE, 0);//接收服务器端信息buf[len] = '\0';//循环的发送接收信息并打印接收信息--recv返回接收到的字节数,sand返回发送的字节数while(1){printf("Enter string to send:\n");scanf("%s", buf);if(!strcmp(buf, "quit")){break;}len = send(sockfd, buf, strlen(buf), 0);len = recv(sockfd, buf, BUFSIZE, 0);buf[len] = '\0';printf("received: %s", buf);}close(sockfd);return 0;}下面则为一个简单的Linux UDP-Socket编程模型:server端:udp_server.c#include #include #include #include #include #define BUFSIZE 100int main(int argc, char *argv[]){int sockfd;int fd;int len;struct sockaddr_in server_addr;//服务器网络地址结构体struct sockaddr_in client_addr;//客户端网络地址结构体int sin_size;char buf[BUFSIZE];//数据传送的缓冲区memset(&server_addr, 0, sizeof(server_addr));//数据传送的缓冲区server_addr.sin_family = AF_INET; //设置为IP通信server_addr.sin_addr.s_addr = INADDR_ANY; //服务器IP地址--允许连接到所有本地地址上server_addr.sin_port = htons(8088); //服务器端口号//创建服务器端套接字--IPv4协议,面向无连接通信,UDP协议if((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0){perror("socket");return -1;}//将套接字绑定到服务器的网络地址上if(bind(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0){perror("bind");return -1;}printf("socket begin receive...\n");//接收客户端的数据并将其发送给客户端--recvfrom是无连接的if((len = recvfrom(sockfd, buf, BUFSIZE, 0, (struct sockaddr*)&client_addr, &sin_size)) < 0){perror("recvfrom");return -1;}printf("received packet from %s:\n", inet_ntoa(client_addr.sin_addr));buf[len] = '\0';printf("contents: %s\n", buf);close(sockfd);return 0;}client端:udp_client.c#include #include #include #include #include #define BUFSIZE 100int main(int argc, char *argv[]){int sockfd;int len;int sin_size;struct sockaddr_in client_addr;char buf[BUFSIZE];memset(&client_addr, 0, sizeof(client_addr));//数据初始化--清零client_addr.sin_family = AF_INET; //设置为IP通信client_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器IP地址client_addr.sin_port = htons(8088); //服务器端口号//创建客户端套接字,面向无连接通信,UDP协议if( (sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0){perror("socket");return -1;}strcpy(buf, "I am a udp messager!");sin_size = sizeof(struct sockaddr_in);//send to serverif((len = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr))) < 0){perror("sendto");return -1;}printf("sending: '%s'\n", buf);close(sockfd);return 0;}

Socket API相关说明:
因为Socket对象是一类特殊的文件,所以可以用Linux系统I/O系统调用read和write函数,来读/写Socket对象。这两个函数对Socket的读写操作默认是以阻塞的方式进行的。
对Socket调用write()行为与将第4个参数flags设置为0的send()的行为完全相同。
通信的类型有本机通信(AF_UNIX/AF_LOCAL)和网络通信(AF_INET)。
端口号的选择:小于1024的端口号是系统所保留的,用户不能随便使用。
在TCP-Socket中,客户端也可以选择监听(listen),但一般不这样做。



原创粉丝点击