Socket是应用层与协议族通信的中间软件抽象层,它是一组接口。
先附图一张,虽然是讲解TCP的socket,但是道理相通
一、基本socket函数
Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符。socket也有一个类似于打
开文件的函数:socket(),调用socket(),该函数返回一个整型的socket的描述符,随后的连接建立、数据传输等操作也都是通过该socket实现。
1、socket函数
syntax:
int socket(int domain, int type, int protocol);
功能说明:
调用成功,返回socket文件描述符;失败,返回-1,并设置errno
参数说明:
domain指明所使用的协议族,通常为PF_INET,表示TCP/IP协议;
type参数指定socket的类型,基本上有三种:数据流套接字、数据报套接字、原始套接字
protocol通常赋值"0"。
两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。socket数据结构中包含这五种信息。
2、bind函数
syntax:
int bind(int sock_fd,struct sockaddr_in *my_addr, int addrlen);
功能说明:
将套接字和指定的端口相连。成功返回0,否则,返回-1,并置errno.
参数说明:
sock_fd是调用socket函数返回值,
my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
struct sockaddr_in结构类型是用来保存socket信息的:
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
addrlen为sockaddr的长度。
3、connect函数
syntax:
int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen);
功能说明:
客户端发送服务请求。成功返回0,否则返回-1,并置errno。
参数说明:
sock_fd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是结构sockaddr_in的长度。
4、listen函数
syntax:
int listen(int sock_fd, int backlog);
功能说明:
等待指定的端口的出现客户端连接。调用成功返回0,否则,返回-1,并置errno.
参数说明:
sock_fd 是socket()函数返回值;
backlog指定在请求队列中允许的最大请求数
5、accecpt函数
syntax:
int accept(int sock_fd, struct sockadd_in* addr, int addrlen);
功能说明:
用于接受客户端的服务请求,成功返回新的套接字描述符,失败返回-1,并置errno。
参数说明:
sock_fd是被监听的socket描述符,
addr通常是一个指向sockaddr_in变量的指针,
addrlen是结构sockaddr_in的长度。
6、write函数
syntax:
ssize_t write(int fd,const void *buf,size_t nbytes)
功能说明:
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量.
在网络程序中,当我们向套接字文件描述符写时有俩种可能:
1)write的返回值大于0,表示写了部分或者是全部的数据.
2)返回的值小于0,此时出现了错误.需要根据错误类型来处理.
如果错误为EINTR表示在写的时候出现了中断错误.
如果错误为EPIPE表示网络连接出现了问题.
7、read函数
syntax:
ssize_t read(int fd,void *buf,size_t nbyte)
函数说明:
read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.
如果错误为EINTR说明读是由中断引起的,
如果错误是ECONNREST表示网络连接出了问题.
note:write和read可以用
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
替代
8、close函数
syntax:
int close(sock_fd);
说明:
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
函数运行成功返回0,否则返回-1
附:service代码:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>#define MYPORT 8887
#define QUEUE 20
#define BUFFER_SIZE 1024int main()
{///定义sockfdint server_sockfd = socket(AF_INET,SOCK_STREAM, 0);///定义sockaddr_instruct sockaddr_in server_sockaddr;server_sockaddr.sin_family = AF_INET;server_sockaddr.sin_port = htons(MYPORT);server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);///bind,成功返回0,出错返回-1if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1){perror("bind");exit(1);}///listen,成功返回0,出错返回-1if(listen(server_sockfd,QUEUE) == -1){perror("listen");exit(1);}///客户端套接字char buffer[BUFFER_SIZE];struct sockaddr_in client_addr;socklen_t length = sizeof(client_addr);///成功返回非负描述字,出错返回-1int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);if(conn<0){perror("connect");exit(1);}while(1){memset(buffer,0,sizeof(buffer));int len = recv(conn, buffer, sizeof(buffer),0);if(strcmp(buffer,"exit\n")==0)break;fputs(buffer, stdout);send(conn, buffer, len, 0);}close(conn);close(server_sockfd);return 0;
}
client代码
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>#define MYPORT 8887
#define BUFFER_SIZE 1024int main()
{///定义sockfdint sock_cli = socket(AF_INET,SOCK_STREAM, 0);///定义sockaddr_instruct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(MYPORT); ///服务器端口servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip///连接服务器,成功返回0,错误返回-1if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){perror("connect");exit(1);}char sendbuf[BUFFER_SIZE];char recvbuf[BUFFER_SIZE];while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL){send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送if(strcmp(sendbuf,"exit\n")==0)break;recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收fputs(recvbuf, stdout);memset(sendbuf, 0, sizeof(sendbuf));memset(recvbuf, 0, sizeof(recvbuf));}close(sock_cli);return 0;
}
运行效果图:
注意:需要先运行services端,然后再运行client端