socket通信
socket是应用层与TCP/IP协议族通信的中间软件抽象层,是一组接口。工作原理如下:

具体过程:服务器端先初始化socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
socket属性
1.创建套接字
套接字的特性由三个属性确定:域(domain), 类型(type)和协议(protocol)。
int socket(int domain, int type, int protocol);
domain:指定socket的类型,一般为AF_INET;
type:是SOCK_STREAM 或SOCK_DGRAM,分别表示TCP连接和UDP连接;
protocol :通常赋值"0"。
socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。
2.命名套接字
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针; //addrlen常被设置为sizeof(struct sockaddr)。
返回值:0表示成功;-1表示遇到错误,并将errno置为相应的错误号。
端口号 : 一般不要置为小于1024的值,因为1~1024是保留端口号 ,可使用大于1024中任何一个没有被占用的端口号。
addr的赋值如下:实现自动获得本机IP地址和随机获取一个没有被占用的端口号。
my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */
3.套接字地址结构
套接字地址由结构sockaddr_in来指定,在头文件 <netinet/in.h> 中定义。
第一个结构:
struct sockaddr {
unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 字节的协议地址 */
};
sa_family:一般为AF_INET; 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同样大小 */
};
sin_family :通常被赋AF_INET;
sin_port和 sin_addr :转换成为网络字节优先顺序 。
sin_zero :用来将sockaddr_in结构填充到与struct sockaddr同样的长度,应该用bzero()或memset()函数将其置为零。
指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,如果一个函数所需参数类型是sockaddr时,可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
IP地址结构 in_addr 被定义为:
struct in_addr{
unsigned long int s_addr;
};
4.创建队列
int listen(int sockfd, int backlog); //backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们
backlog:队列中等待服务的请求数目,系统缺省值为20,常用值是5。
返回值:-1表示遇到错误,errno被置为相应的错误码。
5.阻塞接收
当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器 accept()它 。
int accept(int sockfd, void *addr, int *addrlen); //addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);//addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。
返回值:-1表示错误,并且设置相应的errno值。
6.请求连接
connect()函数用来与远端服务器建立一个TCP连接。
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); //sockfd是目的服务器的sockt描述符;serv_addr是包含目的机IP地址和端口号的指针。
返回值:-1表示遇到错误,并且设置相应的errno值。
7.数据传输
send()和recv()——数据传输
int send(int sockfd, const void *msg, int len, int flags); //sockfd是你想用来传输数据的socket描述符,msg是一个指向要发送数据的指针,Len是以字节为单位的数据的长度。flags一般情况下置为0。
返回值:返回实际发送出的字节数。当send()返回值与len不匹配时,应该对这种情况进行处理。
int recv(int sockfd,void *buf,int len,unsigned int flags);//sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。
返回值:返回实际上接收的字节数,或当出现错误时,返回-1并置相应的errno值。
socket使用
例一:server端:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define MAXLINE 4096
int main( int argc, char** argv )
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
if( ( listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
{
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_addr.s_addr = htonl( INADDR_ANY );
servaddr.sin_port = htons( 6666 );
if( bind( listenfd, ( struct sockaddr* )&servaddr, sizeof( servaddr ) ) == -1 )
{
printf( "bind socket error: %s(errno: %d)\n",strerror( errno ),errno );
exit( 0 );
}
if( listen( listenfd, 10 ) == -1 )
{
printf( "listen socket error: %s(errno: %d)\n",strerror( errno ),errno );
exit( 0 );
}
printf( "======waiting for client's request======\n" );
while( 1 )
{
if( ( connfd = accept( listenfd, ( struct sockaddr* )NULL, NULL ) ) == -1 )
{
printf( "accept socket error: %s(errno: %d)",strerror( errno ),errno );
continue;
}
n = recv( connfd, buff, MAXLINE, 0 );
buff[n] = '\0';
printf( "recv msg from client: %s\n", buff );
close( connfd );
}
close( listenfd );
}
client端:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define MAXLINE 4096
int main( int argc, char** argv )
{
int sockfd, n;
char recvline[4096], sendline[4096];
struct sockaddr_in servaddr;
#if 0
if( argc != 2 )
{
printf( "usage: ./client <ipaddress>\n" );
exit( 0 );
}
#endif
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_addr.s_addr = inet_addr( "109.123.123.36" );
servaddr.sin_port = htons( 6666 );
#if 0
if( inet_pton( AF_INET, argv[1], &servaddr.sin_addr ) <= 0 )
{
printf( "inet_pton error for %s\n",argv[1] );
exit( 0 );
}
#endif
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 );
}
close( sockfd );
exit( 0 );
}
例二:server端:
//s_unix.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/tmp/UNIX.domain"
int main(void)
{
socklen_t clt_addr_len;
int listen_fd;
int com_fd;
int ret;
int i;
static char recv_buf[1024];
int len;
struct sockaddr_un clt_addr;
struct sockaddr_un srv_addr;
listen_fd=socket(PF_UNIX,SOCK_STREAM,0);
if(listen_fd<0)
{
perror("cannot create communication socket");
return 1;
}
//set server addr_param
srv_addr.sun_family=AF_UNIX;
strncpy(srv_addr.sun_path,UNIX_DOMAIN,sizeof(srv_addr.sun_path)-1);
unlink(UNIX_DOMAIN);
//bind sockfd & addr
ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot bind server socket");
close(listen_fd);
unlink(UNIX_DOMAIN);
return 1;
}
//listen sockfd
ret=listen(listen_fd,1);
if(ret==-1)
{
perror("cannot listen the client connect request");
close(listen_fd);
unlink(UNIX_DOMAIN);
return 1;
}
//have connect request use accept
len=sizeof(clt_addr);
com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
if(com_fd<0)
{
perror("cannot accept client connect request");
close(listen_fd);
unlink(UNIX_DOMAIN);
return 1;
}
//read and printf sent client info
printf("\n=====info=====\n");
for(i=0;i<4;i++)
{
memset(recv_buf,0,1024);
int num=read(com_fd,recv_buf,sizeof(recv_buf));
printf("Message from client (%d)) :%s\n",num,recv_buf);
}
close(com_fd);
close(listen_fd);
unlink(UNIX_DOMAIN);
return 0;
}
client端
//c_unix.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/tmp/UNIX.domain"
int main(void)
{
int connect_fd;
int ret;
char snd_buf[1024];
int i;
static struct sockaddr_un srv_addr;
//creat unix socket
connect_fd=socket(PF_UNIX,SOCK_STREAM,0);
if(connect_fd<0)
{
perror("cannot create communication socket");
return 1;
}
srv_addr.sun_family=AF_UNIX;
strcpy(srv_addr.sun_path,UNIX_DOMAIN);
//connect server
ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
perror("cannot connect to the server");
close(connect_fd);
return 1;
}
memset(snd_buf,0,1024);
strcpy(snd_buf,"message from client");
//send info server
for(i=0;i<4;i++)
write(connect_fd,snd_buf,sizeof(snd_buf));
close(connect_fd);
return 0;
}
来源:https://www.cnblogs.com/jeakeven/p/4763881.html