/*** TCP Server tcpserver.c
*
* 利用 socket 介面設計網路應用程式
* 程式啟動後等待 client 端連線,連線後印出對方之 IP 位址
* 並顯示對方所傳遞之訊息,並回送給 Client 端。
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h>
#define SERV_PORT 5134
#define MAXNAME 1024
extern int errno;
main()
{
int socket_fd; /* file description into transport */
int recfd; /* file descriptor to accept */
int length; /* length of address structure */
int nbytes; /* the number of read **/
char buf[BUFSIZ];
struct sockaddr_in myaddr; /* address of this service */
struct sockaddr_in client_addr; /* address of client */
/*
* Get a socket into TCP/IP
*/
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
perror ("socket failed");
exit(1);
}
/*
* Set up our address
*/
bzero ((char *)&myaddr, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(SERV_PORT);
/*
* Bind to the address to which the service will be offered
*/
if (bind(socket_fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) <0) {
perror ("bind failed");
exit(1);
}
/*
* Set up the socket for listening, with a queue length of 5
*/
if (listen(socket_fd, 20) <0) {
perror ("listen failed");
exit(1);
}
/*
* Loop continuously, waiting for connection requests
* and performing the service
*/
length = sizeof(client_addr);
printf("Server is ready to receive !!\n");
printf("Can strike Cntrl-c to stop Server >>\n");
while (1) {
if ((recfd = accept(socket_fd,
(struct sockaddr_in *)&client_addr, &length)) <0) {
perror ("could not accept call");
exit(1);
}
if ((nbytes = read(recfd, &buf, BUFSIZ)) < 0) {
perror("read of data error nbytes !");
exit (1);
}
printf("Create socket #%d form %s : %d\n", recfd,
inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
printf("%s\n", &buf);
/* return to client */
if (write(recfd, &buf, nbytes) == -1) {
perror ("write to client error");
exit(1);
}
close(recfd);
printf("Can Strike Crtl-c to stop Server >>\n");
}
}
/* TCP Client program (tcpclient.c)
*
* 本程式啟動後向 Server (tcpserver) 要求連線,
* 並送出某檔案給 Server,再由 Server 收回該檔案
* 並顯示出該檔案的內容
*
*/
#include <stdio.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#define SERV_PORT 5134
#define MAXDATA 1024
#define MAXNAME 1024
main(argc, argv)
int argc;
char **argv;
{
int fd; /* fd into transport provider */
int i; /* loops through user name */
int length; /* length of message */
int fdesc; /* file description */
int ndata; /* the number of file data */
char data[MAXDATA]; /* read data form file */
char data1[MAXDATA]; /*server response a string */
char buf[BUFSIZ]; /* holds message from server */
struct hostent *hp; /* holds IP address of server */
struct sockaddr_in myaddr; /* address that client uses */
struct sockaddr_in servaddr; /* the server's full addr */
/*
* Check for proper usage.
*/
if (argc < 3) {
fprintf (stderr,
"Usage: %s host_name(IP address) file_name\n", argv[0]);
exit(2);
}
/*
* Get a socket into TCP/IP
*/
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror ("socket failed!");
exit(1);
}
/*
* Bind to an arbitrary return address.
*/
bzero((char *)&myaddr, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
if (bind(fd, (struct sockaddr *)&myaddr,
sizeof(myaddr)) <0) {
perror("bind failed!");
exit(1);
}
/*
* Fill in the server's address and the data.
*/
bzero((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
hp = gethostbyname(argv[1]);
if (hp == 0) {
fprintf(stderr,
"could not obtain address of %s\n", argv[2]);
return (-1);
}
bcopy(hp->h_addr_list[0], (caddr_t)&servaddr.sin_addr,
hp->h_length);
/*
* Connect to the server連線.
*/
if (connect(fd, (struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0) {
perror("connect failed!");
exit(1);
}
/**開起檔案讀取文字 **/
fdesc = open(argv[2], O_RDONLY);
if (fdesc == -1) {
perror("open file error!");
exit (1);
}
ndata = read (fdesc, data, MAXDATA);
if (ndata < 0) {
perror("read file error !");
exit (1);
}
data[ndata] = '\0';
/* 發送資料給 Server */
if (write(fd, data, ndata) == -1) {
perror("write to server error !");
exit(1);
}
/** 由伺服器接收回應 **/
if (read(fd, data1, MAXDATA) == -1) {
perror ("read from server error !");
exit (1);
}
/* 印出 server 回應 **/
printf("%s\n", data1);
close (fd);
}
Makefileall:tcpserver tcpclient
tcpserver:tcpserver.c
gcc $^ -o $@
tcpclient:tcpclient.c
gcc $^ -o $@
底下是另一個TCP Client的範例
用C實作TCP socket連接/讀/寫,使用fcntl設定nonblocking以處理connect overtime情況,使用select來處理socket讀寫overtime。
/*
* on Unix:
* cc -c connector.c
* cc -o connector connector.o
*
* on Windows NT:
* open connector.c in Visual Studio
* press 'F7' to link -- a project to be created
* add wsock32.lib to the link section under project setting
* press 'F7' again
*
* running:
* type 'connector' for usage
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
#define MAX_STRING_LEN 1024
#define BUFSIZE 2048
#ifndef WIN32
#define SOCKET int
#else
#define errno WSAGetLastError()
#define close(a) closesocket(a)
#define write(a, b, c) send(a, b, c, 0)
#define read(a, b, c) recv(a, b, c, 0)
#endif
char buf[BUFSIZE];
static char i_host[MAX_STRING_LEN]; /* site name */
static char i_port[MAX_STRING_LEN]; /* port number */
void err_doit(int errnoflag, const char *fmt, va_list ap);
void err_quit(const char *fmt, ...);
int tcp_connect(const char *host, const unsigned short port);
void print_usage();
//xnet_select x defines
#define READ_STATUS 0
#define WRITE_STATUS 1
#define EXCPT_STATUS 2
/*
s - SOCKET
sec - timeout seconds
usec - timeout microseconds
x - select status
*/
SOCKET xnet_select(SOCKET s, int sec, int usec, short x)
{
int st = errno;
struct timeval to;
fd_set fs;
to.tv_sec = sec;
to.tv_usec = usec;
FD_ZERO(&fs);
FD_SET(s, &fs);
switch(x){
case READ_STATUS:
st = select(s+1, &fs, 0, 0, &to);
break;
case WRITE_STATUS:
st = select(s+1, 0, &fs, 0, &to);
break;
case EXCPT_STATUS:
st = select(s+1, 0, 0, &fs, &to);
break;
}
return(st);
}
int tcp_connect(const char *host, const unsigned short port)
{
unsigned long non_blocking = 1;
unsigned long blocking = 0;
int ret = 0;
char * transport = "tcp";
struct hostent *phe; /* pointer to host information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
SOCKET s; /* socket descriptor and socket type */
int error;
#ifdef WIN32
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
/* Tell the user that we couldn't find a usable */
/* WinSock DLL. */
printf("can't initialize socket library\n");
exit(0);
}
}
#endif
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
if ((sin.sin_port = htons(port)) == 0)
err_quit("invalid port \"%d\"\n", port);
/* Map host name to IP address, allowing for dotted decimal */
if ( phe = gethostbyname(host) )
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )
err_quit("can't get \"%s\" host entry\n", host);
/* Map transport protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
err_quit("can't get \"%s\" protocol entry\n", transport);
/* Allocate a socket */
s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
if (s < 0)
err_quit("can't create socket: %s\n", strerror(errno));
/* Connect the socket with timeout */
#ifdef WIN32
ioctlsocket(s,FIONBIO,&non_blocking);
#else
ioctl(s,FIONBIO,&non_blocking);
#endif
//fcntl(s,F_SETFL, O_NONBLOCK);
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1){
struct timeval tv;
fd_set writefds;
// 设置连接超时时间
tv.tv_sec = 10; // 秒数
tv.tv_usec = 0; // 毫秒
FD_ZERO(&writefds);
FD_SET(s, &writefds);
if(select(s+1,NULL,&writefds,NULL,&tv) != 0){
if(FD_ISSET(s,&writefds)){
int len=sizeof(error);
//下面的一句一定要,主要针对防火墙
if(getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0)
goto error_ret;
if(error != 0)
goto error_ret;
}
else
goto error_ret; //timeout or error happen
}
else goto error_ret; ;
#ifdef WIN32
ioctlsocket(s,FIONBIO,&blocking);
#else
ioctl(s,FIONBIO,&blocking);
#endif
}
else{
error_ret:
close(s);
err_quit("can't connect to %s:%d\n", host, port);
}
return s;
}
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAX_STRING_LEN];
errno_save = errno;
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
fflush(stdout);
fputs(buf, stderr);
fflush(NULL);
return;
}
/* Print a message and terminate. */
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
#ifdef WIN32
char *optarg;
char getopt(int c, char *v[], char *opts)
{
static int now = 1;
char *p;
if (now >= c) return EOF;
if (v[now][0] == '-' && (p = strchr(opts, v[now][1]))) {
optarg = v[now+1];
now +=2;
return *p;
}
return EOF;
}
#else
extern char *optarg;
#endif
#define required(a) if (!a) { return -1; }
int init(int argc, char *argv[])
{
char c;
//int i,optlen;
//int slashcnt;
i_host[0] = '\0';
i_port[0] = '\0';
while ((c = getopt(argc, argv, "h:p:?")) != EOF) {
if (c == '?')
return -1;
switch (c) {
case 'h':
required(optarg);
strcpy(i_host, optarg);
break;
case 'p':
required(optarg);
strcpy(i_port, optarg);
break;
default:
return -1;
}
}
/*
* there is no default value for hostname, port number,
* password or uri
*/
if (i_host[0] == '\0' || i_port[0] == '\0')
return -1;
return 1;
}
void print_usage()
{
char *usage[] =
{
"Usage:",
" -h host name",
" -p port",
"example:",
" -h 127.0.0.1 -p 4001",
};
int i;
for (i = 0; i < sizeof(usage) / sizeof(char*); i++)
printf("%s\n", usage[i]);
return;
}
int main(int argc, char *argv[])
{
SOCKET fd;
int n;
/* parse command line etc ... */
if (init(argc, argv) < 0) {
print_usage();
exit(1);
}
buf[0] = '\0';
/* pack the info into the buffer */
strcpy(buf, "HelloWorld");
/* make connection to the server */
fd = tcp_connect(i_host, (unsigned short)atoi(i_port));
if(xnet_select(fd, 0, 500, WRITE_STATUS)>0){
/* send off the message */
write(fd, buf, strlen(buf));
}
else{
err_quit("Socket I/O Write Timeout %s:%s\n", i_host, i_port);
}
if(xnet_select(fd, 3, 0, READ_STATUS)>0){
/* display the server response */
printf("Server response:\n");
n = read(fd, buf, BUFSIZE);
buf[n] = '\0';
printf("%s\n", buf);
}
else{
err_quit("Socket I/O Read Timeout %s:%s\n", i_host, i_port);
}
close(fd);
#ifdef WIN32
WSACleanup();
#endif
return 0;
}
資料來源:
http://140.127.138.46/tsnien/Teach_Manu/F7858/Aid/tcpserver.c
http://140.127.138.46/tsnien/Teach_Manu/F7858/Aid/tcpclient.c
http://www.zeali.net/entry/13
沒有留言:
張貼留言