慶應義塾大学
2007年度 秋学期
ネットワーク・プログラミング(C言語)
Network Programming in C
第3回 10月23日 Lecture 4, October 23:
Basic socket programming 1
Outline of This Lecture
- What's a Socket?
- Socket Operation
- Server Example Code
- Tools
- Homework
What's a Socket? aka Internet Protocol addressing (v4/v6)
Last week, we talked about identifiers for Internet connections. The
data structure and programming paradigm we use for those connections
is known as a socket, and the identifier that makes a unique
socket is:
- Local Address (IPv4 or IPv6)
- Local Port number (if ULP is TCP or UDP)
- Remote Address (IPv4 or IPv6)
- Remote Port number (if ULP is TCP or UDP)
- Upper-Layer Protocol identifier (e.g., TCP or UDP)
Once a connection is established, sending and receiving data on both
the client and server is similar. However, getting the socket started
is a little different on the client than on the server.
For Internet services using TCP or UDP, your service name is
your port number. Important services use well-known port
numbers, assigned by the IANA.
Socket Operation
Let's look at how a server uses sockets. Using a stream,
or connection-oriented protocol such as TCP is easier. The
following steps must be done:
- Create the socket by calling socket()
- Call bind() to create an address (especially
the port number)
- Use listen() to control the number of connections
that the socket will support
- accept() a new connection (this creates a new
socket for you!)
- Use read() and write() to receive
and send data
- shutdown() the connection socket when you're done
- close() the connection socket
- Return to accept() and wait for the next incoming
connection
Server Example Code
// Server code in C
// adapted from http://en.wikipedia.org/wiki/Berkeley_sockets
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int main()
{
struct addrinfo hint;
struct sockaddr_storage bindaddr_storage;
struct sockaddr_in6 *bindaddr6 =
(struct sockaddr_in6 *)&bindaddr_storage;
struct sockaddr_in *bindaddr =
(struct sockaddr_in *)&bindaddr_storage;
struct addrinfo *result;
struct sockaddr_storage peer;
int peersize;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
int retval;
int i32SocketFD = socket(PF_INET6, SOCK_STREAM, 0);
char msg[] = "Success!\n";
if(-1 == i32SocketFD)
{
perror("can not create socket");
exit(-1);
}
bzero(&bindaddr_storage, sizeof(bindaddr_storage));
bindaddr6->sin6_family = AF_INET6;
bindaddr6->sin6_addr = in6addr_any; /* struct assignment */
bindaddr6->sin6_port = htons(12345);
if(-1 == bind(i32SocketFD,(struct sockaddr*) bindaddr6,
sizeof(struct addrinfo)))
{
printf("error bind failed");
perror("main");
exit(-1);
}
if(-1 == listen(i32SocketFD, 10))
{
printf("error listen failed");
exit(-1);
}
// Here, you should print out your local address using
// getsockname() and getnameinfo() (and gai_strerror on error)
for(; ;)
{
int i32ConnectFD = accept(i32SocketFD, NULL, NULL);
if(0 > i32ConnectFD)
{
// improve error reporting here, using perror()
printf("error accept failed");
exit(-1);
}
// Here, you should print out your local address
// and the peer address using
// getsockname(), getpeername(), and getnameinfo()
// (and gai_strerror on error)
// perform read write operations ...
// add error checking and reporting here
write(i32ConnectFD, msg, sizeof(msg));
// wait one minute; this lets us see the connection in place, and
// even see the behavior as we try to start a second connection
// at the same time
sleep(60);
// add error checking and reporting here
shutdown(i32ConnectFD, 2);
// add error checking and reporting here
close(i32ConnectFD);
}
// add error checking and reporting here
close(i32SocketFD);
return 0;
}
Your operation, after some of the modifications in the homework,
should look something like this:
Tools
Many tools for monitoring network traffic and debugging the packets
that go by are available.
- tcpdump (the original network monitor, perhaps)
- Wireshark
- netstat
- (if you don't know about ifconfig, you should)
宿題
Homework
This week's homework (submit via email):
- Take the above program, and edit where the comments are to print
out information about the connections,
using getnameinfo(), getpeerinfo(),
and gai_strerror().
- Test for errors from the system calls in the above code.
Use perror() where appropriate.
- Modify the above server so that it calls fork()
and creates a second process after accepting the connection. The
parent should close() the connection socket and
return to waiting for a new connection, while the
child should close the initial socket, process the connection, then
exit.
- Learn to use a wire monitoring tool, such as Wireshark or
tcpdump. Capture the packets of two connections to your server to
show that both connections are being processed at the same time.
Next Lecture
第4回 10月30日
Lecture 4, October 30: Basic socket programming 2
Additional Information
その他