我不得不说socket编程对于我来说是很复杂的,以前总是说socket,但到现在来说还是没有把他弄懂,即使当时记得了但过了几天又忘记了,所以需要常常看才能牢记。
socket编程的基础函数有socket(),bind(), listen(),accept(),send(),sendto(),recv(),recvfrom()根据客户端还是服务端不一样,针对udp,tcp又是不一样的,先对这几个函数进行说明
socket()------该函数用于建立一个socket连接,可以指定socket类型等信息,在建立socket连接之后,可以对sockaddr或sockaddr_in结构体进行初始化,来保存所建立的socket
地址信息
bind()---------用于将本地ip绑定到端口号,绑定其他ip不能成功,主要用于TCP中,在upd中则没有必要
listen()--------在创建套接字和绑定地址之后需要在该套接字上接受新的请求,listen()可以用来创建一个等待队列,用于存放未处理的客户端请求
accept()-------服务端调用listen之后,调用此函数等待并接收客户端的请求,通常他从listen()函数创建的等待队列中取出第一个未处理的连接请求
connetc()------在TCP中用于bind()之后的客户端用于与服务器建立连接,而在UDP中由于没有bind()函数,这个connect函数有点类似于bind()函数的作用
recv(),recv()---用于数据的发送和接收,在udp中可以在connet()建立连接之后再使用
sendto(),recvfrom()---在TCP中作用等同于send(),recv(),而在UDP中可以用在之前没有使用connect()的情况,这两个函数可以自动寻找指定地址并进行连接
服务器和客户端使用TCP协议的流程如下:
对于客户端有时不需要进行bind()调用,http://blog.csdn.net/smilestone322/article/details/8449165
服务器和客户端使用UDP协议的流程如下:
下面是各个函数的使用语法:
socket()使用语法:
bind()函数的使用语法:
端口号和地址在my_addr中给出,如果不指定地址则内核随意分配一个临时端口给程序
listen()函数语法如下:
accept()函数语法如下:
connect()函数语法如下:
send()函数语法:
recv函数语法:
sendto语法:
recvfrom函数语法:
下面是一个c/s的例子
server.c
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 4321
#define BUFFER_SIZE 1024
#define MAX_QUE_CONN_NM 5
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr ;
int sin_size, recvbytes ;
int sockfd,client_fd ;
char buf[BUFFER_SIZE] ;
/*建立socket连接*/
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket") ;
exit(1) ;
}
printf("socket id = %d\n", sockfd) ;
/*sockaddr_in结构体相关参数*/
server_sockaddr.sin_family = AF_INET ;
server_sockaddr.sin_port = htons(PORT) ;
server_sockaddr.sin_addr.s_addr = INADDR_ANY ;
bzero(&(server_sockaddr.sin_zero), 8) ;
int i = 1 ;//允许重复使用本地地址与套接字进行绑定
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) ;
//绑定ip与端口号
if (bind(sockfd, (struct sockaddr *)&server_sockaddr,
sizeof (struct sockaddr)) == -1)
{
perror("bind error") ;
exit(1) ;
}
printf("bind success\n") ;
/*调用listen()函数,创建未处理请求队列*/
if (listen(sockfd, MAX_QUE_CONN_NM) == -1)
{
perror("listen error\n") ;
exit (1) ;
}
printf("listen....\n") ;
//等待客户连接,此处返回客户端的socket描述符
if((client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr,
&sin_size)) == -1)
{
perror("accept") ;
exit(1) ;
}
memset(buf, 0, sizeof(buf)) ;
/*调用recv()函数接收客户端请求*/
if ((recvbytes = recv(client_fd, buf, BUFFER_SIZE, 0)) == -1)
{
perror("recv") ;
exit(1) ;
}
printf("recevie a message :%s\n", buf) ;
close(sockfd) ;
exit(0) ;
}
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 4321
#define BUFFER_SIZE 1024
int main(int argc, char *argv[])
{
int sockfd, sendbytes ;
char buf[BUFFER_SIZE] ;
struct hostent *host ;
struct sockaddr_in serv_addr ;
if (argc < 3)
{
fprintf(stderr, "USAGE: ./client Hostname(or ip address) Text\n") ;
exit(1) ;
}
//由主机名获得ip
if ((host = gethostbyname(argv[1])) == NULL)
{
perror("gethostbyname") ;
exit(1) ;
}
memset(buf, 0, sizeof(buf)) ;
sprintf(buf, "%s", argv[2]) ;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) ==-1)
{
perror("socket") ;
exit(1) ;
}
serv_addr.sin_family = AF_INET ;
serv_addr.sin_port = htons(PORT) ;
serv_addr.sin_addr = *((struct in_addr*)host->h_addr) ;
bzero(&(serv_addr.sin_zero), 8) ;
if (connect(sockfd, (struct sockaddr*)&serv_addr,
sizeof(struct sockaddr)) == -1)
{
perror("connetc") ;
exit(1) ;
}
if ((sendbytes = send(sockfd, buf, strlen(buf), 0)) == -1)
{
perror("send") ;
exit (1) ;
}
close(sockfd) ;
exit(0) ;
}
执行客户端:
服务端将会接收消息: