1
/*
socket->bind->listen->accept->recv/recvfrom->send/sendto->close
2
3
客戶端:socket->connect->send/sendto->recv/recvfrom->close
4
5
其中服務器端首先建立起socket,然后調用本地端口的綁定,接著就開始與客服端建立聯系,并接收客戶端發送的消息。
6
客戶端則在建立socket之后調用connect函數來建立連接。
7
8
服務器端的源代碼如下所示:
*/
9
10
/*
"server.c"
*/
11
12
#include<sys/types.h>
13
#include<sys/socket.h>
14
#include<stdio.h>
15
#include<stdlib.h>
16
#include<errno.h>
17
#include<
string
.h>
18
#include<unistd.h>
19
#include<netinet/
in
.h>
20
21
#define
PORT 3490
//
端口
22
23
#define
BUFFER_SIZE 1024
//
緩沖區大小
24
25
#define
MAX_QUE_CONN_NM 5
//
服務器等待連接隊列的最大長度。
26
27
int
main(){
28
29
struct
sockaddr_in server_sockaddr,client_sockaddr;
//
分別定義服務器和客戶端套接字
30
int
sin_size,recvbytes;
31
int
server_fd,client_fd;
32
char
buf[BUFFER_SIZE];
//
緩沖區
33
34
/*
35
SOCKET PASCAL FAR socket( int af, int type, int protocol);
36
af:一個地址描述。目前僅支持AF_INET格式,也就是說ARPA Internet地址格式。
37
type:指定socket類型。新套接口的類型描述類型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。
38
常用的socket類型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
39
protocol:顧名思義,就是指定協議。套接口所用的協議。如調用者不想指定,可用0。
40
常用的協議有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,
41
它們分別對應TCP傳輸協議、UDP傳輸協議、STCP傳輸協議、TIPC傳輸協議。
42
*/
43
if
((server_fd = socket(AF_INET,SOCK_STREAM,
0
))== -
1
){
//
建立socket連接www.linuxidc.com
44
perror(
"
create socket fail
"
);
45
exit(
1
);
46
}
47
48
printf(
"
Socket id=%d\n
"
,server_fd);
49
50
/*
設置sockaddr_in結構體中的相關參數
*/
51
52
server_sockaddr.sin_family =
AF_INET;
53
server_sockaddr.sin_port = htons(PORT);
//
由于在寫網絡程序時字節的網絡順序和主機順序會有問題
54
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
//
即0.0.0.0 任意地址
55
bzero(&(server_sockaddr.sin_zero),
8
);
56
int
i =
1
;
//
允許重復使用本地地址與套接字進行綁定
57
58
/*
int PASCAL FAR setsockopt(SOCKET s,int level,int optname,const char FAR *optval,int optlen);
59
s:標識一個套接字的描述符。
60
level:選項定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。
61
optname:需設置的選項。
62
optval:指針,指向存放選項值的緩沖區。
63
optlen:optval緩沖區長度。
64
*/
65
setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&i,
sizeof
(i));
66
67
/*
68
int bind(SOCKET socket, const struct sockaddr *address,
69
socklen_t address_len);
70
參數說明:
71
socket:是一個套接字。
72
address:是一個sockaddr結構指針,該結構中包含了要結合的地址和端口號。
73
address_len:確定address緩沖區的長度。
74
返回值:如果函數執行成功,返回值為0,否則為SOCKET_ERROR。
75
*/
76
if
(bind(server_fd,(
struct
sockaddr *)&server_sockaddr,
sizeof
(
struct
sockaddr)) == -
1
){
//
綁定函數bind
77
perror(
"
bind fail
"
);
78
exit(
1
);
79
}
80
81
printf(
"
Bind success!\n
"
);
82
83
/*
84
int PASCAL FAR listen( SOCKET s, int backlog);
85
S:用于標識一個已捆綁未連接套接口的描述字。
86
backlog:等待連接隊列的最大長度。
87
*/
88
if
(listen(server_fd,MAX_QUE_CONN_NM)== -
1
){
//
調用listen函數,創建為處理請求的隊列
89
perror(
"
listen fail
"
);
90
exit(
1
);
91
}
92
93
printf(
"
Listening......\n
"
);
94
95
/*
96
SOCKET PASCAL FAR accept( SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen);
97
s:套接口描述字,該套接口在listen()后監聽連接。
98
addr:(可選)指針,指向一緩沖區,其中接收為通訊層所知的連接實體的地址。Addr參數的實際格式由套接口創建時所產生的地址族確定。
99
addrlen:(可選)指針,輸入參數,配合addr一起使用,指向存有addr地址長度的整型數。
100
*/
101
if
((client_fd = accept(server_fd,(
struct
sockaddr *)&client_sockaddr,&sin_size))==-
1
){
//
調用accept函數,等待客戶端的接
102
perror(
"
accept fail
"
);
103
exit(
1
);
104
}
105
106
printf(
"
server: got connection from %s \n
"
,inet_ntoa(client_sockaddr.sin_addr));
107
108
memset(buf,
0
,
sizeof
(buf));
109
/*
110
int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);
111
s:一個標識已連接套接口的描述字。
112
buf:用于接收數據的緩沖區。
113
len:緩沖區長度。
114
flags:指定調用方式。通常寫成0
115
*/
116
if
((recvbytes = recv(client_fd,buf,BUFFER_SIZE,
0
)) == -
1
){
//
調用recv函數接收客戶端的請求
117
perror(
"
recv fail
"
);
118
exit(
1
);
119
}
120
121
printf(
"
Received a message: %s\n
"
,buf);
122
123
124
/*
向客戶起寫數據
*/
125
if
(write(client_fd,
"
客戶端我收到你發來的數據了,你能收到這句應答嗎?\n
"
,
1024
)==-
1
)
126
perror(
"
write error!
"
);
127
128
close(client_fd);
129
130
close(server_fd);
131
exit(
0
);
132
}
133
134
135
136
137
138
/*
客戶端
*/
139
/*
client.c 運行方式:./client localhost
*/
140
#include <stdio.h>
141
#include <stdlib.h>
142
#include <errno.h>
143
#include <
string
.h>
144
#include <netdb.h>
145
#include <sys/types.h>
146
#include <netinet/
in
.h>
147
#include <sys/socket.h>
148
#define
PORT 3490
149
#define
MAXDATASIZE 5000
150
int
main(
int
argc,
char
**
argv)
151
{
152
int
sockfd,nbytes;
153
char
buf[
1024
];
154
struct
hostent *
he;
155
struct
sockaddr_in srvaddr;
156
if
(argc!=
2
)
157
{
158
perror(
"
Usage:client hostname\n
"
);
159
exit(
1
);
160
}
161
/*
函數gethostbyname獲得指定域名地址所對應的ip地址
*/
162
if
((he=gethostbyname(argv[
1
]))==
NULL)
163
{
164
perror(
"
gethostbyname
"
);
165
exit(
1
);
166
}
167
/*
創建套接字,返回套接字描述符
*/
168
if
((sockfd=socket(AF_INET,SOCK_STREAM,
0
))==-
1
)
169
{
170
perror(
"
create socket error
"
);
171
exit(
1
);
172
}
173
bzero(&srvaddr,
sizeof
(srvaddr));
174
/*
用獲得的遠程服務器進程的ip地址和端口號來填充一個internet套接字地址結構
*/
175
srvaddr.sin_family=
AF_INET;
176
srvaddr.sin_port=
htons(PORT);
177
srvaddr.sin_addr=*((
struct
in_addr *)he->
h_addr);
178
/*
用connect于這個遠程服務器建立一個internet連接
*/
179
if
(connect(sockfd,(
struct
sockaddr *)&srvaddr,
sizeof
(
struct
sockaddr))==-
1
)
180
{
181
perror(
"
connect error
"
);
182
exit(
1
);
183
}
184
185
186
if
((send(sockfd,
"
客戶端向服務端發送數據,服務端你收到了嗎?
"
,
1024
,
0
)) == -
1
)
187
{
188
perror(
"
send error
"
);
189
exit(
1
);
190
}
191
192
193
194
/*
調用read函數讀取服務器write過來的信息
*/
195
if
((nbytes=read(sockfd,buf,MAXDATASIZE))==-
1
)
196
{
197
perror(
"
read error
"
);
198
exit(
1
);
199
}
200
buf[nbytes]=
'
\0
'
;
201
printf(
"
read: %s
"
,buf);
202
close(sockfd);
203
}
?
運行方式: gcc -o service service.c
gcc -o client client.c
chmod +x service
chmod +x client
在一個終端運行:./service
在另一個終端運行:./client localhost
服務端輸出:
Socket id=3 Bind success! Listening...... server: got connection from 127.0.0.1 Received a message: 客戶端向服務端發送數據,服務端你收到了嗎?
?
客戶端輸出:
read: 客戶端我收到你發來的數據了,你能收到這句應答嗎?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

