一、socket地址api。socket最开始的含义是一个IP地址和端口对。他唯一地表示了使用TCP通信的一端。(主要讨论ipv4)
1、ipv4socket地址:
1
2
3
4
5
6
7
8
9
10
|
struct
sockaddr_in
{
sa_family_t sin_family;
/*地址族:AF_INET*/
u_int16 sin_port;
/*端口号,要用网络字节序表示*/
struct
in_addr sin_addr;
/*ipv4地址结构*/
};
struct
in_addr
{
u_int32_t s_addr;
/*ipv4地址,要用网络字节表示*/
};
|
2、ip地址转换函数
1
2
3
4
5
6
7
8
9
10
11
|
/*字符串转in_addr*/
#include<arpa/inet.h>
int
inet_aton(
const
char
*strptr,
struct
in_addr *addrptr);
in_addr_t inet_addr(
const
char
*strptr);
int
inet_pton(
int
family,
const
char
*strptr,
void
*addrptr);
/*in_addr转字符串*/
char
*inet_ntoa(
struct
in_addr inaddr);
const
char
*inet_ntop(
int
family,
const
void
*addrptr,
char
*strptr,
size_t
len);
|
其中inet_pton和inet_ntop不仅可以转换ipv4地址,而且可以转换ipv6的地址。
二、socket基础API。创建socket、命名socket、监听、socket、接收连接、发起连接、读写数据、获取地址信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#include<sys/types.h>
#include<sys/socket.h>
/*创建socket*/
int
socket(
int
domain,
int
type,
int
protocol);
/*domain表示那个协议,对于TCP/IP协议而言是PF_INET/PT_INET6;type服务类型,TCP使用
SOCK_STREAML(流服务)、UDP使用SOCK_DGRAM(数据报);protocol一般情况都是0
调用成功返回一个socket文件描述符,失败返回-1并设置errno*/
/*绑定或命名socket*/
int
bind(
int
sockfd,
const
struct
sockaddr* my_addr,socklen_t addrlen);
/*将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数是socket地址长度
调用成功返回0,失败返回-1并设置errno。*/
/*监听socket*/
int
listen(
int
sockfd,
int
backlog);
/*sockfd参数指定被监听的socket;backlog提示内核监听队列的最大长度,典型值是5。
调用成功返回0,失败返回-1并设置errno。*/
/*接受连接*/
int
accept(
int
sockfd,
struct
sockaddr *addr,socklen_t* addrlen);
/*sockfd参数是执行过listen系统调用的监听socket。addr参数用来获取接收连接的远端socket地址
,该socket地址长度由addrlen参数指出。
调用成功返回一个新的连接socket,该socket唯一地标识了被接收的这个连接,服务器可以通过读写该
socket来与被接受连接对应的客户端通信。失败时返回-1并设置errno*/
/*向服务器发送连接*/
int
connect(
int
sockfd,
const
struct
sockaddr *serv_addr,socklen_t addrlen);
/*sockfd 参数有socket系统调用返回一个socket。serv_addr参数是服务器监听的socket地址,addlen
参数指定这个地址的长度。
调用成功返回0。一旦成功建立连接,sockfd就唯一地标识了这个连接,客户端就可以通过读写sockfd
来与服务器通信。失败返回-1并设置errno*/
/*从socket上读取数据,向socket上写数据*/
ssize_t recv(
int
sockfd,
void
*buf,
size_t
len,
int
flags);
ssize_t send(
int
sockfd,
const
void
*buf,
size_t
len,
int
flags);
/*recv读取sockfd上的数据,buf和len参数分别指定缓冲区的位置和大小,flags参数通常是0
send往sockfd上写入数据,buf和len参数分别指定写缓冲区的位置和大小。*/
/*关闭socket*/
#include<unistd.h>
int
close(
int
fd);
|
三、使用TCP协议的socket编程的流程如下图
根据上面流程编写client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#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,rec_len;
char
recvline[4096], sendline[4096];
char
buf[MAXLINE];
struct
sockaddr_in servaddr;
if
( argc != 2){
printf
(
"usage: ./client <ipaddress>\n"
);
exit
(0);
}
/*创建socket*/
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_port = htons(8000);
/*转换socket地址*/
if
( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
printf
(
"inet_pton error for %s\n"
,argv[1]);
exit
(0);
}
/*向服务器发起连接*/
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);
/*往socket上写数据*/
if
( send(sockfd, sendline,
strlen
(sendline), 0) < 0)
{
printf
(
"send msg error: %s(errno: %d)\n"
,
strerror
(
errno
),
errno
);
exit
(0);
}
/*从socket上读数据*/
if
((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) {
perror
(
"recv error"
);
exit
(1);
}
buf[rec_len] =
'\0'
;
printf
(
"Received : %s "
,buf);
/*关闭socket*/
close(sockfd);
exit
(0);
}
|
server.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#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 DEFAULT_PORT 8000
#define MAXLINE 4096
int
main(
int
argc,
char
** argv)
{
int
socket_fd, connect_fd;
struct
sockaddr_in servaddr;
char
buff[4096];
int
n;
/*创建Socket */
if
( (socket_fd = 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(DEFAULT_PORT);
//设置的端口为DEFAULT_PORT
/*将本地地址绑定到所创建的套接字上*/
if
( bind(socket_fd, (
struct
sockaddr*)&servaddr,
sizeof
(servaddr)) == -1){
printf
(
"bind socket error: %s(errno: %d)\n"
,
strerror
(
errno
),
errno
);
exit
(0);
}
/*开始监听是否有客户端连接*/
if
( listen(socket_fd, 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
( (connect_fd = accept(socket_fd, (
struct
sockaddr*)NULL, NULL)) == -1){
printf
(
"accept socket error: %s(errno: %d)"
,
strerror
(
errno
),
errno
);
continue
;
}
/*接受客户端传过来的数据*/
n = recv(connect_fd, buff, MAXLINE, 0);
/*向客户端发送回应数据*/
if
(send(connect_fd,
"Hello,you are connected!\n"
, 26,0) == -1)
perror
(
"send error"
);
buff[n] =
'\0'
;
printf
(
"recv msg from client: %s\n"
, buff);
close(connect_fd);
}
close(socket_fd);
}
|
运行结果:
1、运行server程序
2、运行client程序
3、server接收成功
本文转自 8yi少女的夢 51CTO博客,原文链接:http://blog.51cto.com/zhaoxiaohu/1973867,如需转载请自行联系原作者