Network Programming(五)

之前的例子都是TCP的应用,之后这两个例子是关于UDP的

UDPsocket使用模式

实例五

写一个client和server,server显示client的端口号和地址,并返回client发送过去的message的镜像(如client发送ALO,server返回OLA)

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
客户端
# include <sys/socket.h>
# include <netdb.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <arpa/inet.h> //inet_addr

# define SERVERPORT 9999
# define LOCALHOST "127.0.0.1"

# define MYMSGLEN 2048


void question ( int sock, char * msg, struct sockaddr_in * addr, struct sockaddr_in * from )
{
int code, length, ret ;
socklen_t len;

// Send the length of the string.
length = strlen ( msg ) ; // + 1 ;

// Send the string of characters.
len = sizeof ( struct sockaddr_in ) ;
code = sendto ( sock, msg, length, 0, ( struct sockaddr * ) addr, len ) ;
if ( code == -1 ) {
perror ( "sendto" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

// Wait for the answer.
memset ( msg, 0, length ) ;
len = sizeof ( * from ) ;

code = recvfrom ( sock, ( char * ) msg, length, 0, ( struct sockaddr * ) from, & len ) ;
if ( code == -1 ) {
perror ( "recvfrom" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

// Empty message!!!! 0 value returned in UDP mode does not mean closing a connection since there is no connection
// We release the resource and exit the program anyway
if ( code == 0 )
{
// Release ressources.
code = close ( sock ) ;
if ( code == -1 ) {
perror ( "close" ) ;

}
exit ( 1 ) ;
}

}


int main ( int argc, char * argv [ ] )
{
int item ;
socklen_t len;
// Ask for the string of characters.
char string [ MYMSGLEN ] ;


// Create UDP socket and init server address structure.
int sock ;
sock = socket ( AF_INET, SOCK_DGRAM, 0 ) ;
if ( sock == -1 ) {
perror ( "socket" ) ;
exit ( 1 ) ;
}



// Initialisation of the sockaddr_in data structure

struct sockaddr_in addr ;


memset ( & addr, 0, sizeof ( struct sockaddr_in ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( SERVERPORT ) ;
addr . sin_addr . s_addr = inet_addr ( LOCALHOST ) ;


while ( 1 )
{
memset ( string, 0, sizeof( string ) ) ;

printf ( "\n----------------------------------------------------------------------\n" ) ;
printf ( "Please type a message to transfer for processing:" ) ;
item = scanf ( "%[^\n]%*c", string ) ; //reads a hole line till a new line feed
//This is in case of empty message
if ( item == 0 )
{
scanf("%*c");
continue;
}

printf ( "The message being sent is: '%s' \n", string ) ;
printf( "----------------------------------------------------------------------\n" ) ;


if ( !memcmp ( "quit#", string, 5 ) )
{
printf ( " Client exiting upon user request \n" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

// Ask the question and wait for the answer.
struct sockaddr_in from ;

question ( sock, string, & addr, & from ) ;


// Display the result.
printf ( "\n----------------------------------------------------------------------\n" ) ;
printf ( "The processed message is received from server %s, with port number: %d \n" , inet_ntoa( from.sin_addr ), ntohs( from.sin_port ) ) ;

printf ( "The message is : %s\n", string ) ;

printf ( "----------------------------------------------------------------------\n" ) ;
}

return ( 0 ) ;
}

客户端编程思路:
第一步:创建socket,注意:sock = socket ( AF_INET, SOCK_DGRAM, 0 ) ;这时模式是SOCK_DGRAM
第二步,bind地址:与TCP相似地址存在sockaddr_in中,记住先把addr各位置0
第三步,在while(1)中,不断读入字符串scanf(“%[^\n]%c”),这里用到了正则表达式%[^ n]扫描所有内容,直到 \n,但不扫描 \n。星号()告诉它丢弃所扫描的任何内容。%c扫描单个字符,在本例中,该字符是%[^\n]所剩余的\n。星号指示scanf放弃已扫描的字符。
第四步,判断client是否输入”quit#”
第五步,调用question(),其中利用sendto向server发送msg,利用recvfrom从server接受。
第六步,输出信息

ssize_t sendto(int sockfd,const void buf,size_t len,int flags,const struct sockaddr dest_addr,socklen_t addrlen);
用来向另一个socket传送message
需要指定目标地址
flags:特殊设置,通常是0
返回传送的字节数
-1 error

ssize_t recvfrom(int sockfd,void buf,size_t len,int flags,struct sockaddr src_addr, socklen_t* addrlen);
用来从一个socket接受message
src_addr调用之后被填充
flags:特殊设置,通常是0
返回接受的字节数
-1 error

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
服务器
# include <sys/socket.h>
# include <netdb.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <arpa/inet.h> //inet_addr

# define SERVERPORT 9999
# define LOCALHOST "127.0.0.1"

# define MYMSGLEN 2048


void mirror ( char * msg )
{
int i ;
int length ;
char car ;

length = strlen ( msg ) ;

for ( i = 0 ; i < ( length / 2 ) ; i ++ )
{
car = msg [ i ] ;
msg [ i ] = msg [ length - i - 1 ] ;
msg [ length - i - 1 ] = car ;
}
}



void answer_client ( int sock )
{
struct sockaddr_in from ;
socklen_t len;
// Receive the length of the string.
int code, length ;
char string [ MYMSGLEN ];

// Receive the string of characters.

while ( 1 )
{
memset ( string, 0, MYMSGLEN );

len = sizeof ( from ) ;

length = recvfrom ( sock, string, MYMSGLEN, 0,( struct sockaddr * ) & from, & len ) ;

if ( length == -1 ) {
perror ( "recvfrom" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

printf ( "Request received from: %s, with port number: %d \n" , inet_ntoa( from.sin_addr ), ntohs( from.sin_port ) ) ;

if ( length == 0 ) {
printf("Ignoring empty message received \n");

continue ;
}
printf ( "Received message: %s\n", string ) ;
// Check the string of characters.

mirror ( string ) ;

// Prepare the answer

// Return the answer.
len = sizeof ( from ) ;
code = sendto ( sock, string, length, 0, ( struct sockaddr * ) & from, len ) ;
if ( code == -1 ) {
perror ( "sendto" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

// Release ressources.

}


}

int naming ( )
{
// Socket creation.
int sock ;
sock = socket ( AF_INET, SOCK_DGRAM, 0 ) ;
if ( sock == -1 ) {
perror ( "socket" ) ;
exit ( 1 ) ;
}

// Reuse the same port (useful when developing...).
int code, enable = 1;
code = setsockopt ( sock, SOL_SOCKET, SO_REUSEADDR, & enable, sizeof ( int ) ) ;
if (code == -1 ) {
perror ( "setsockopt" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

// Initialisation of the sockaddr_in data structure.
struct sockaddr_in addr ;
memset ( & addr, 0, sizeof ( struct sockaddr_in ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( SERVERPORT ) ;
addr . sin_addr . s_addr = inet_addr ( LOCALHOST ) ;

// Name the socket.
code = bind ( sock, ( struct sockaddr * ) & addr, sizeof ( struct sockaddr_in ) ) ;
if ( code == -1 ) {
perror ( "bind" ) ;
close ( sock ) ;
exit ( 1 ) ;
}

// Return the socket ID.
return ( sock ) ;
}

int main ( int argc, char * argv [ ] )
{
// Name the socket.
int sock ;

sock = naming ( ) ;


// Answering incoming requests.
printf ( "UDP Mirror server ready to process client requests \n" ) ;
answer_client ( sock ) ;


// This point in the program will never be reached.
return ( 0 ) ;
}

服务器编程思路:
第一步:编写服务器处理程序,这里就是mirror()
第二步:通过naming创建socket,设置和bind地址,这一步可以和client一样写在main中
第三步:调用answer_client(),在while(1)中,接受client的msg,处理,返回结果。