1、创建socket对象
//from /usr/include/sys/socket.h
int socket(int domain,int type,int protocol);
函数执行成功,返回一个socket文件描述符,执行失败返回-1。
函数第1个参数用来指明该socket要使用的地址协议簇,即通信协议类型,常用的选项如下:
#define PF_LOCAL 1 /* 本地通信 ,即AF_LOCAL*/
#define PF_UNIX PF_LOCAL /* 本地通信 */
#define PF_FILE PF_LOCAL /* 本地通信 */
#define PF_INET 2 /* IPV4协议簇,即AF_INET */
#define PF_AX25 3 /* AX.25 */
#define PF_IPX 4 /* Novell网协议 */
#define PF_INET6 10 /* IPV6协议簇 */
函数的第2个参数指定socket的类型,选项如下:
//from /usr/include/bits/socket.h
enum __socket_type
{
SOCK_STREAM = 1; //TCP
SOCK_DGRAM = 2; //UDP
SOCK_RAM = 3; //原始套接字
};
函数第3个参数指定使用协议簇中哪个协议,若为0,字系统自动选择。
2、绑定本地IP地址和端口
//from /usr/include/sys/socket.h
int bind(int socket,struct sockaddr* addr,sockelen_t len);
函数执行成功返回0,执行失败返回-1。
函数第1个参数为socket套接字。
函数第2个参数为一个指向strcut sockaddr的指针,根据socket不同的协议类型,其结构也不同,原始定义相对复杂,下面是我整理后的结构体定义,可以直接使用:
/* Structure describing a generic socket address. */
struct sockaddr
{
uint16 sa_family; /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
uint16 sin_family; /* Address family AF_INET */
uint16 sin_port; /* Port number. */
uint32 sin_addr.s_addr; /* Internet address. */
unsigned char sin_zero[8]; /* Pad to size of `struct sockaddr'. */
};
/* Ditto, for IPv6. */
struct sockaddr_in6
{
uint16 sin6_family; /* Address family AF_INET6 */
uint16 sin6_port; /* Transport layer port # */
uint32 sin6_flowinfo; /* IPv6 flow information */
uint8 sin6_addr[16]; /* IPv6 address */
uint32 sin6_scope_id; /* IPv6 scope-id */
};
3、服务器监听网络(服务器)
//from /usr/include/sys/socket.h
int listen(int socket,int num);
该函数使socket套接字变为监听套接字,准备接受客户端的连接,执行成功返回0,失败返回-1。
函数第1个参数为一个socket套接字。
函数第2个参数为客户端请求连接的排队个数。
4、客户端发起连接
//from /usr/include/sys/socket.h
int connect(int socket,struct sockaddr* addr,sockelen_t len );
函数执行成功,则与地址为addr的服务器建立连接,并返回0,失败返回-1。
函数第1个参数为一个socket套接字。
函数第2个参数为服务器地址,第3个参数为地址长度。
5、服务器建立连接
//from /usr/include/sys/socket.h
int accept(int socket,struct sockaddr* addr,sockelen_t len );
该函数将阻塞等待客户端的连接,如果执行成功,函数将返回一个新的socket套接字,从而使原套接字继续等待其他客户端的连接,执行失败返回-1。
函数第1个参数为绑定服务器端口地址的socket套接字。
函数第2个参数用来存储接受到的客户端的端口和地址,第3个参数为地址长度。
6、TCP发送接收数据
//from /usr/include/sys/socket.h
/*向socket发送首地址为buf,长度为len的数据*/
size_t send(int socket,void* buf,size_t len,int flags);
/*从socket接收数据并保存在首地址为buf,长度为len的地址中*/
size_t recv(int socket,void* buf,size_t len,int flags);
若flags为0,则以上函数同read/write函数,为阻塞方式,若为MSG_DONTWAIT,则为非阻塞方式,函数执行成功返回读写数据的大小,失败返回-1。
7、关闭套接字
close(int socket);
int shutdown(int socket,int how);
函数shutdown()可以根据参数how指定关闭套接字的某一端:
how = 0:关闭socket的读端,即往socket写数据使正常的。
how = 1:关闭socket的写端,即往socket读数据使正常的。
how = 2:读写通道均关闭,同close()。
8、UDP发送数据
//from /usr/include/sys/socket.h
ssize_t sendto(int sockfd,void* buf,size_t len,int flags,struct sockaddr* addr,sockelen_t len );
函数第1个参数表示从本地哪个socket描述符发送数据
函数第2个参数表示欲发送的数据首地址
函数第3个参数表示欲发送的数据长度
函数第4个参数flags若为0,则以上函数同read/write函数,为阻塞方式,若为MSG_DONTWAIT,则为非阻塞方式
函数第5个参数表示目标主机的地址信息
函数第6个参数表示目标主机的地址信息占内存大小。
函数执行成功,返回发送的数据大小,失败返回-1。
9、UDP接收数据
ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* addr,sockelen_t* len );
函数第1个参数表示从本地哪个socket描述符接收数据
函数第2个参数表示接收的数据保存的位置
函数第3个参数表示欲接收的数据长度
函数第4个参数flags若为0,则以上函数同read/write函数,为阻塞方式,若为MSG_DONTWAIT,则为非阻塞方式
函数第5个参数表示源主机的地址信息
函数第6个参数表示源主机的地址信息占内存大小。
函数执行成功,返回接收的数据大小,失败返回-1
10、获取socket本地及对端信息
int getsockname(int socket,struct sockaddr* addr,socklen_t* len);
int getpeername(int socket,struct sockaddr* addr,socklen_t* len);
函数getsockname()获取套接字socket(已经至少完成绑定工作的)的地址信息,并保存在长度为len的addr地址中,成功返回0,失败返回-1。
函数getpeername()仅可以获取一个已经连接上服务器的套接字的远程信息,如IP地址、端口等,结果保存在长度为len的addr地址中,成功返回0,失败返回-1
以下是自己写的一个C/S架构的简单例子,主要练习以上函数的用法:
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#define SERVERPORT 8888
#define SERVERADDR "192.168.103.128"
void* recvmsgs(void* pSockfd)
{
char buf[1024];
int* socket;
if(NULL == pSockfd)
{
printf("recvmsg fail!\n");
return;
}
socket= (int*)pSockfd;
while(1)
{
memset(buf,0,sizeof(buf));
recv(*socket,buf,1024,0);
printf("recv a msg:%s\n",buf);
sleep(1);
}
return;
}
int main()
{
int opt = 1;
int ret = -1;
socklen_t len;
pthread_t tid = -1;
int newfd = -1;
int sockfd = -1;
char buffer[1024];
struct sockaddr_in server,clienaddr;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket fail!\n");
return -1;
}
memset(&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(SERVERPORT);
server.sin_addr.s_addr = INADDR_ANY;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
if(-1 == bind(sockfd,(struct sockaddr*)&server,sizeof(server)))
{
perror("connect fail!\n");
return -1;
}
if(-1 == listen(sockfd,1))
{
perror("listen error!\n");
return -1;
}
len = sizeof(struct sockaddr);
while((newfd= accept(sockfd,(struct sockaddr*)&clienaddr,&len)) != -1)
{
printf("newfd:%d,clienaddr:sin_family=%d,sin_port=%d,s_addr=%s\n",newfd,clienaddr.sin_family,ntohs(clienaddr.sin_port),inet_ntoa(clienaddr.sin_addr));
ret = pthread_create(&tid,NULL,recvmsgs,(void*)&newfd);
if(-1 == ret)
{
perror("pthread_create fail\n");
return -1;
}
}
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#define SERVERPORT 8888
#define SERVERADDR "192.168.103.128"
void* recvmsgs(void* pSockfd)
{
char buf[1024];
int* socket;
if(NULL == pSockfd)
{
printf("recvmsg fail!\n");
return;
}
socket= (int*)pSockfd;
while(1)
{
memset(buf,0,sizeof(buf));
recv(*socket,buf,1024,0);
printf("recv a msg:%s\n",buf);
sleep(1);
}
return;
}
int main()
{
int ret = -1;
pthread_t tid = -1;
pthread_t tid2 = -1;
int sockfd = -1;
char buffer[1024];
struct sockaddr_in server;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket fail!\n");
return -1;
}
memset(&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(SERVERPORT);
server.sin_addr.s_addr = inet_addr(SERVERADDR);
if(-1 == connect(sockfd,(struct sockaddr*)&server,sizeof(server)))
{
perror("connect fail!\n");
return -1;
}
ret = pthread_create(&tid,NULL,recvmsgs,(void*)&sockfd);
if(-1 == ret)
{
perror("pthread_create fail\n");
return -1;
}
while(1)
{
memset(buffer,0,sizeof(buffer));
gets(buffer);
send(sockfd,buffer,1024,0);
sleep(1);
}
return 0;
}